笔记:threadx netx使用BSD封装层创建UDP客户端

BSD封装层

引用维基百科的一段描述:伯克利套接字(英语:Internet Berkeley sockets) ,又称为BSD 套接字(BSD sockets)是一种应用程序接口(API),用于网络套接字( socket)与Unix域套接字,包括了一个用C语言写成的应用程序开发库,主要用于实现进程间通讯,在计算机网络通讯方面被广泛使用。
它有一套标准的套接字接口,与底层分离,这样的话,程序就可以方便的互相兼容,目前netx支持的套接字接口有:socket、bind、listen等,更详细的内容可以参考官方文档(链接)。
虽然BSD封装层兼容性比较好,但是很占内存,实际使用时根据需求取舍。

我的开发及测试环境

软件:keil MDK、nc(netcat)
硬件:STM32F407、LAN8720A
首先你需要有一个移植了netx的能ping通网络的工程,这个工程的话可以参考我的上一篇文章进行搭建(链接在此),然后添加上BSD封装层代码,再写一个UDP客户端程序就行了。

添加BSD层

将netx源码内的addons\BSD目录的内容添加到工程中,效果如下:

在nx_port.h文件内添加上使能BSD封装层的宏定义:

#define NX_ENABLE_EXTENDED_NOTIFY_SUPPORT

此时编译整个工程,会出现两个错误一个警告,错误是因为TX_THREAD_STRUCT这个数据结构内少了一个字段,找到TX_THREAD_STRUCT的定义,然后添加上这个字段就行了,警告可以不管。

在TX_THREAD_STRUCT这个数据结构的末尾有这样一个宏是留给用户进行扩展的,为了不破坏源码的结构,我选择使用这个宏进行扩展,以此解决这个错误:


现在编译已经没有错误了,接下来添加BSD层的初始化,这个可以参考netx\samples\demo_bsd_udp.c文件:

/* 定义BSD封装层线程的栈大小 */
#define BSD_SOCKET_STACK 2048
/* 定义BSD封装层线程的栈空间 */
CHAR 		bsd_socket_stack[BSD_SOCKET_STACK];

/* Now initialize BSD Socket Wrapper */
status = (UINT)bsd_initialize (&ip_0, &pool_0, bsd_socket_stack, BSD_SOCKET_STACK, 2);

if (status)
	error_counter++;

编写udp线程

直接贴源码,也可以参考netx\samples\demo_bsd_udp.c文件:

#include "tx_api.h"
#include "nx_api.h"
#include "nx_bsd.h"

#include "debug.h"

#define APP_UDP_CLIENT_STACK 512

#define SERVER_PORT 50000

TX_THREAD thread_udp_client;

static void app_udp_client(ULONG thread_input);

void app_udp_client_create(TX_BYTE_POOL *pool)
{
	char *pointer = TX_NULL;
	
	tx_byte_allocate(pool,(void **)&pointer,APP_UDP_CLIENT_STACK,TX_NO_WAIT);
	if(!pointer)
	{
		PRINTF("%s failed..\r\n",app_udp_client_create);
		return ;
	}
	
	tx_thread_create(&thread_udp_client,"udp client",app_udp_client,0,pointer,APP_UDP_CLIENT_STACK,3,3,TX_NO_TIME_SLICE,TX_AUTO_START);
}

static void app_udp_client(ULONG thread_input)
{
	int status;
	int sockfd;
	int addrlen;
	struct sockaddr_in serveraddr;
	struct sockaddr_in peeraddr;
	char recv_buf[64];
	char send_buf[] = {"hello server..\r\n"};
	
	sockfd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	if(sockfd == ERROR)
	{
		PRINTF("socket failed..\r\n");
		return ;
	}
	
	memset(&serveraddr,0,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	// 服务端IP
	serveraddr.sin_addr.s_addr = htonl(IP_ADDRESS(192,168,0,12));
	// 服务端端口号
	serveraddr.sin_port = htons(SERVER_PORT);
	
	for(;;)
	{
		status = sendto(sockfd,send_buf,sizeof(send_buf),0,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
		if(status == ERROR)
		{
			PRINTF("sendto failed..\r\n");
			continue ;
		}
		
		memset(recv_buf,0,sizeof(recv_buf));
		addrlen = sizeof(struct sockaddr_in);
		status = recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&peeraddr,&addrlen);
		if(status == ERROR)
		{
			PRINTF("recvfrom failed..\r\n");
		}
		else
		{
			PRINTF("recv:%s\r\n",recv_buf);
		}
		
		tx_thread_sleep(NX_IP_PERIODIC_RATE);
	}
	
	soc_close(sockfd);
}

然后在tx_application_define函数中调用app_udp_client_create就行了,注意入参是为线程创建申请的字节池,也可用全局数组的方式。

测试验证

确保你的udp服务端和板子之间网络是通的,我是用的虚拟机里面的ubuntu,用nc工具(如果没有的话可以网上搜索安装)创建的一个udp服务端,命令如下:

# 50000对应程序里面的服务端端口
nc -u -l 50000

命令执行后,服务端就会一直阻塞住,这时我们给板子上电,网卡工作后,就会看到服务端收到了hello server…这一段内容,这就是前面udp客户端程序里面写好的,然后我们在服务端输入内容,客户端也可以正确的收到发过来的内容。由于测试机不能联网,所以贴不了效果图。点我获取本文源码

欢迎扫码关注我的微信公众号
漫长当下

猜你喜欢

转载自blog.csdn.net/a1598025967/article/details/107688905