引用维基百科的一段描述:伯克利套接字(英语: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客户端程序就行了。
将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++;
直接贴源码,也可以参考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客户端程序里面写好的,然后我们在服务端输入内容,客户端也可以正确的收到发过来的内容。由于测试机不能联网,所以贴不了效果图。点我获取本文源码。