最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=104619
第9章 ThreadX NetXDUO之TCP客户端
本章节为大家讲解NetXDUO的TCP客户端实现,学习本章节前,务必要优先学习第7章TCP传输控制协议基础知识。有了这些基础知识之后,再搞本章节会有事半功倍的效果。
9.1 初学者重要提示
9.2 TCP客户端API函数
9.3 TCP客户端的实现方法
9.4 网络调试助手和板子的调试操作步骤
9.5 实验例程说明
9.6 总结
9.1 初学者重要提示
1、学习本章节前,务必保证已经学习了第7章的基础知识。
2、本章要掌握的函数稍多,可以先学会基本的使用,然后再深入了解这些函数使用时的注意事项,争取达到熟练使用。
3、socket和监听的关系:
- 创建的一个socket只能创建一个监听。
- 创建的一个socket不能够监听多个 。
- 创建多个socket可以创建多个监听。
- 创建多个socket可以仅创建一个监听。
4、ThreadX NetXDUO的TCP Socket数据包申请和释放问题
- 函数nx_tcp_socket_receive 会申请一个NX_PACKET数据包用于接收,如果用户不使用了必须使用函数nx_packet_release释放。
- 使用函数nx_tcp_socket_send必须有申请好的NX_PACKET数据包,可以使用函数nx_packet_allocate申请,也可以使用nx_tcp_socket_receive申请的。
特别要注意的地方来了,函数nx_tcp_socket_send调用后会释放nx_packet_allocate或者nx_tcp_socket_receive申请的数据包。无需用户再去调用函数nx_packet_release释放。
9.2 TCP客户端API函数
下面一张图说明ThreadX NetXDUO TCP Socket的各种API玩法:
9.2.1 函数nx_system_initialize
函数原型:
VOID nx_system_initialize(VOID);
函数描述:
NetXDUO初始化,所有其它功能调用之前必须优先调用此函数。
9.2.2 函数nx_packet_pool_create
函数原型:
代码语言:javascript复制UINT nx_packet_pool_create(
NX_PACKET_POOL *pool_ptr,
CHAR *name,
ULONG payload_size,
VOID *memory_ptr,
ULONG memory_size);
函数描述:
此函数用于数据包内存池创建
函数参数:
- 第1个参数是内存池控制块的地址。
- 第2个参数是内存池名字。
- 第3个参数是内存池中每个数据包的字节数。 此值必须至少为 40 个字节,并且还必须可以被 4 整除。
- 第4个参数是内存池中数据地址,此地址必须ULONG对齐。
- 第5个参数是内存池大小。
- 返回值:
- NX_SUCCESS:(0x00) 创建内存池成功。
- NX_PTR_ERROR:(0x07) 第1个参数地址无效。
- NX_SIZE_ERROR:(0x09) 第5个参数内存池大小无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
使用举例:
代码语言:javascript复制 /* 创建内存池 */
status = nx_packet_pool_create(&pool_0, /* 内存池控制块 */
"NetX Main Packet Pool",/* 内存池名 */
1536, /* 内存池每个数据包大小,单位字节此值必须至少为 40 个字节,并且还必须可以被 4 整除 */
(ULONG*)(((int)packet_pool_area 15) & ~15) ,/* 内存池地址,此地址必须ULONG对齐 */
NX_PACKET_POOL_SIZE); /* 内存池大小 */
9.2.3 函数nx_ip_create
函数原型:
代码语言:javascript复制UINT nx_ip_create(
NX_IP *ip_ptr,
CHAR *name, ULONG ip_address,
ULONG network_mask,
NX_PACKET_POOL *default_pool,
VOID (*ip_network_driver)(NX_IP_DRIVER *),
VOID *memory_ptr,
ULONG memory_size,
UINT priority);
函数描述:
此函数使用用户提供的 IP 地址,数据包内存内存池和网络驱动程序创建 IP 实例。注意,直到 IP任务执行之后,才会调用网络驱动。
函数参数:
- 第1个参数是创建IP实例的控制块指针。
- 第2个参数是IP实例的名字。
- 第3个参数是IP地址。
- 第4个参数是子网掩码
- 第5个参数是内存池地址。
- 第6个参数是网卡驱动地址。
- 第7个参数是IP任务栈地址
- 第8个参数是IP任务栈大小,单位字节。
- 第9个参数是IP任务优先级。
- 返回值
- NX_SUCCESS:(0x00) 创建 IP 实例成功。
- NX_NOT_IMPLEMENTED:(0x4A) 未正确配置 NetX Duo 库。
- NX_PTR_ERROR:(0x07) IP控制块地址、网络驱动函数指针、内存池地址或任务栈地址无效。
- NX_SIZE_ERROR:(0x09) 提供的任务栈大小太小。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_IP_ADDRESS_ERROR:(0x21) 提供的 IP 地址无效。
- NX_OPTION_ERROR:(0x21) 提供的 IP 任务优先级无效。
使用举例:
代码语言:javascript复制/* 例化IP */
status = nx_ip_create(&ip_0, /* IP实例控制块 */
"NetX IP Instance 0", /* IP实例名 */
IP_ADDRESS(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3), /* IP地址 */
0xFFFFFF00UL, /* 子网掩码 */
&pool_0, /* 内存池 */
nx_driver_stm32h7xx, /* 网卡驱动 */
(UCHAR*)AppTaskNetXStk, /* IP任务栈地址 */
sizeof(AppTaskNetXStk), /* IP任务栈大小,单位字节 */
APP_CFG_TASK_NETX_PRIO); /* IP任务优先级 */
9.2.4 函数nx_arp_enable
函数原型:
代码语言:javascript复制UINT nx_arp_enable(
NX_IP *ip_ptr,
VOID *arp_cache_memory,
ULONG arp_cache_size);
函数描述:
此函数用于使能ARP地址解析。
函数参数:
- ip_ptr:IP实例地址。
- arp_cache_memory:ARP缓存地址。
- arp_cache_size:每个 ARP 条目均为 52 个字节,因此,ARP 条目总数是52字节整数倍。
- 返回值
- NX_SUCCESS:(0x00) 启用 ARP 成功。
- NX_PTR_ERROR:(0x07) IP实例地址或ARP缓存地址无效。
- NX_SIZE_ERROR:(0x09) 用户提供的 ARP 缓存内存太小。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_ALREADY_ENABLED:(0x15) 此组件已启用。
使用举例:
代码语言:javascript复制int32_t tcp_sock;
tcp_sock = netTCP_GetSocket (tcp_cb_server);
if (tcp_sock > 0)
{
res = netTCP_Listen (tcp_sock, PORT_NUM);
}
if(netTCP_SendReady(tcp_sock) == true )
{
}
9.2.5 函数nx_ip_fragment_enable
函数原型:
UINT nx_ip_fragment_enable(NX_IP *ip_ptr);
函数描述:
此函数用于启用 IPv4 和 IPv6 数据包分段和重组功能。创建 IP 任务时,此服务会自动禁用。
函数参数:
1、第1个参数是IP实例地址。
2、返回值
- NX_SUCCESS:(0x00) 启用 IP 分段成功。
- NX_PTR_ERROR:(0x07) IP 实例地址无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_NOT_ENABLED:(0x14) IP 分段功能未编译到 NetX Duo 中。
使用举例:
代码语言:javascript复制 /* 使能fragment */
status = nx_ip_fragment_enable(&ip_0);
9.2.6 函数nx_tcp_enable
函数原型:
UINT nx_tcp_enable(NX_IP *ip_ptr);
函数描述:
此函数用于使能TCP组件。
函数参数:
1、第1个参数是IP实例地址。
2、返回值
- NX_SUCCESS:(0x00) 启用 TCP 成功。
- NX_ALREADY_ENABLED:(0x15) TCP 已启用。
- NX_PTR_ERROR:(0x07) IP 实例地址无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
使用举例:
代码语言:javascript复制 /* 使能TCP */
status = nx_tcp_enable(&ip_0);
9.2.7 函数nx_tcp_client_socket_bind
函数原型:
代码语言:javascript复制UINT nx_tcp_client_socket_bind(
NX_TCP_SOCKET *socket_ptr,
UINT port,
ULONG wait_option);
函数描述:
此函数用于为创建的TCP Socket绑定端口。如果设置的端口号还不可用,可以设置等待时间。
函数参数:
1、第1个参数是TCP Socket指针。
2、第2个参数是绑定的端口,范围1 -65535。如果设置为NX_ANY_PORT(0x0000),则会搜索一个可用端口号。
3、第3个参数是端口号不可用时,等待时间定义:
- NX_NO_WAIT (0x00000000)
- NX_WAIT_FOREVER (0xFFFFFFFF)
- 等待时间:(0x00000001 到 0xFFFFFFFE),单位是ThreadX系统时钟节拍。
4、返回值
- NX_SUCCESS:(0x00) 绑定TCP Socket成功。
- NX_ALREADY_BOUND:(0x22) 此TCP Socket已与另一 TCP 端口绑定。
- NX_PORT_UNAVAILABLE:(0x23) 端口已与其他Socket绑定。
- NX_NO_FREE_PORTS:(0x45) 没有可用的端口。
- NX_WAIT_ABORTED:(0x1A) 已通过调用 tx_thread_wait_abort 中止请求。
- NX_INVALID_PORT:(0x46) 端口无效。
- NX_PTR_ERROR:(0x07) Socket指针无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_NOT_ENABLED:(0x14) 此组件尚未启用。
使用举例:
代码语言:javascript复制 /* 绑定端口 */
ret = nx_tcp_client_socket_bind(&TCPSocket, DEFAULT_PORT, NX_WAIT_FOREVER);
if (ret != NX_SUCCESS)
{
Error_Handler(__FILE__, __LINE__);
}
9.2.8 函数nx_tcp_client_socket_unbind
函数原型:
UINT nx_tcp_client_socket_unbind(NX_TCP_SOCKET *socket_ptr);
函数描述:
此函数用于解除TCP Socket绑定的端口。
函数参数:
1、 第1个参数是TCP Socket指针。
2、 返回值
- NX_SUCCESS:(0x00) 取消绑定Socket成功。
- NX_NOT_BOUND:(0x24) Socket未与任何端口绑定。
- NX_NOT_CLOSED:(0x35) Socket尚未断开连接。
- NX_PTR_ERROR:(0x07) Socket指针无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_NOT_ENABLED (0x14) 尚未启用此组件。
使用举例:
代码语言:javascript复制 /* 绑定端口 */
ret = nx_tcp_client_socket_bind(&TCPSocket, DEFAULT_PORT, NX_WAIT_FOREVER);
if (ret != NX_SUCCESS)
{
Error_Handler(__FILE__, __LINE__);
}
9.2.9 函数nx_tcp_client_socket_connect
函数原型:
代码语言:javascript复制UINT nx_tcp_client_socket_connect(
NX_TCP_SOCKET *socket_ptr,
ULONG server_ip,
UINT server_port,
ULONG wait_option);
函数描述:
此函数用于创建TCP客户端连接远程服务器。
函数参数:
1、 第1个参数是TCP Socket指针。
2、 第2个参数是远程服务器IP。
3、 第3个参数是远程端口。
4、 第4个参数连接远程服务器的等待选项,支持的参数如下:
- NX_NO_WAIT (0x00000000)
- NX_WAIT_FOREVER (0xFFFFFFFF)
- 等待时间:(0x00000001 到 0xFFFFFFFE),单位是ThreadX系统时钟节拍。
5、 返回值:
- NX_SUCCESS:(0x00) 连接套接字成功。
- NX_NOT_BOUND:(0x24) 套接字未绑定。
- NX_NOT_CLOSED:(0x35) 套接字未处于关闭状态。
- NX_IN_PROGRESS (0x37) 未指定等待,正在尝试连接。
- NX_INVALID_INTERFACE:(0x4C) 提供了无效的接口。
- NX_WAIT_ABORTED:(0x1A) 已通过调用 tx_thread_wait_abort 中止所请求的挂起。
- NX_IP_ADDRESS_ERROR:(0x21) 服务器 IP 地址无效。
- NX_INVALID_PORT (0x46) 端口无效。
- NX_PTR_ERROR:(0x07) 套接字指针无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_NOT_ENABLED (0x14) 尚未启用此组件。
使用举例:
代码语言:javascript复制 /* 连接远程服务器 */
ret = nx_tcp_client_socket_connect(&TCPSocket, TCP_SERVER_ADDRESS, TCP_SERVER_PORT, NX_WAIT_FOREVER);
if (ret != NX_SUCCESS)
{
Error_Handler(__FILE__, __LINE__);
}
9.2.10 函数nx_tcp_socket_info_get
函数原型:
代码语言:javascript复制UINT nx_tcp_socket_info_get(
NX_TCP_SOCKET *socket_ptr,
ULONG *tcp_packets_sent,
ULONG *tcp_bytes_sent,
ULONG *tcp_packets_received,
ULONG *tcp_bytes_received,
ULONG *tcp_retransmit_packets,
ULONG *tcp_packets_queued,
ULONG *tcp_checksum_errors,
ULONG *tcp_socket_state,
ULONG *tcp_transmit_queue_depth,
ULONG *tcp_transmit_window,
ULONG *tcp_receive_window);
函数描述:
用于获取TCP Socket相关信息。
函数参数:
- 第1个参数是TCP Socket指针。
- 第2个参数是发送的TCP数据包总数目。
- 第3个参数是发送的TCP总字节数。
- 第4个参数是接收的TCP数据包总数目。
- 第5个参数是接收的TCP总字节数。
- 第6个参数是重新传输的TCP数据包总数目。
- 第7个参数是Socket上TCP排队的TCP数据包总数。
- 第8个参数是Socket上有校验和错误的TCP数据包总数。
- 第9个参数是Socket当前状态。
- 第10个参数是仍在排队等待ACK的发送数据包总数。
- 第11个参数是当前发送窗口大小。
- 第12个参数是当前接收窗口大小。
- 返回值:
- NX_SUCCESS:(0x00) 检索 TCP Socket信息成功。
- NX_PTR_ERROR:(0x07) Socket指针无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_NOT_ENABLED:(0x14) 此组件尚未启用。
使用举例:
代码语言:javascript复制 /* 获取socket状态 */
nx_tcp_socket_info_get(&TCPSocket, /* TCP Socket控制块 */
NULL, /* 发送的TCP数据包总数目 */
NULL, /* 发送的TCP总字节数 */
NULL, /* 接收TCP数据包总数目 */
NULL, /* 接收的TCP总字节数 */
NULL, /* 重新传输的TCP数据包总数目 */
NULL, /* Socket上TCP排队的TCP数据包总数 */
NULL, /* Socket上有校验和错误的TCP数据包总数 */
&socket_state, /* Socket当前状态 */
NULL, /* 仍在排队等待ACK的发送数据包总数 */
NULL, /* 当前发送窗口大小 */
NULL); /* 当前接收窗口大小 */
9.2.11 函数nx_tcp_socket_receive
函数原型:
代码语言:javascript复制UINT nx_tcp_socket_receive(
NX_TCP_SOCKET *socket_ptr,
NX_PACKET **packet_ptr,
ULONG wait_option);
函数描述:
此函数用于从指定的Socket接收TCP数据,如果指定的Socket上没有已经排队的数据,则调用方会根据提供的等待选项参数挂起。
函数参数:
1、 第1个参数是TCP Socket指针
2、 第2个参数是TCP数据包指针。
3、 第3个参数是Socket队列上没有数据时的处理:
- NX_NO_WAIT (0x00000000)。
- NX_WAIT_FOREVER (0xFFFFFFFF)。
- 以时钟周期为单位的超时值(0x00000001 到 0xFFFFFFFE)。
4、 返回值:
- NX_SUCCESS:(0x00) 接收Socket数据成功。
- NX_NOT_BOUND:(0x24) Socket未绑定。
- NX_NO_PACKET:(0x01) 未收到任何数据。
- NX_WAIT_ABORTED:(0x1A) 通过调用 tx_thread_wait_abort 中止挂起。
- NX_NOT_CONNECTED:(0x38) 该Socket不再处于已连接状态。
- NX_PTR_ERROR:(0x07) Socket指针或返回数据包指针无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_NOT_ENABLED:(0x14) 此组件尚未启用。
注意事项:
- 如果返回了 NX_SUCCESS,则应用程序负责:不再需要收到数据包时将其释放。
使用举例:
代码语言:javascript复制/* 接收TCP客户端发的TCP数据包 */
ret = nx_tcp_socket_receive(&TCPSocket, /* TCP Socket控制块 */
&data_packet, /* 接收到的数据包 */
NX_WAIT_FOREVER); /* 永久等待 */
9.2.12 函数nx_tcp_socket_send
函数原型:
代码语言:javascript复制UINT nx_tcp_socket_send(
NX_TCP_SOCKET *socket_ptr,
NX_PACKET *packet_ptr,
ULONG wait_option);
函数描述:
此函数用于TCP Socket数据发送。 如果接收方最近一次建议的窗口大小低于此请求,则此函数可以根据指定的等待参数挂起。此函数可保证不会将大于 MSS 的数据包数据发送到 IP 层。
函数参数:
1、 第1个参数是TCP Socket句柄。
2、 第2个参数是TCP数据包指针。
3、 第3个参数是发送的数据包大于接收方窗口大小时的参数处理,支持如下参数:
- NX_NO_WAIT (0x00000000)
- NX_WAIT_FOREVER (0xFFFFFFFF)
- 以时钟周期为单位的超时值(0x00000001 到 0xFFFFFFFE)
4、 返回值,返回以下几种状态值:
- NX_SUCCESS:(0x00) Socket发送成功。
- NX_NOT_BOUND:(0x24) Socket未与任何端口绑定。
- NX_NO_INTERFACE_ADDRESS:(0x50) 找不到合适的传出接口。
- NX_NOT_CONNECTED:(0x38) 套接字不再处于已连接状态。
- NX_WINDOW_OVERFLOW:(0x39) 请求大于接收方所播发的窗口大小(以字节为单位)。
- NX_WAIT_ABORTED:(0x1A) 已通过调用 tx_thread_wait_abort 中止所请求的挂起。
- NX_INVALID_PACKET:(0x12) 数据包未分配。
- NX_TX_QUEUE_DEPTH:(0x49) 已达到最大传输队列深度。
- NX_OVERFLOW:(0x03) 数据包追加指针无效。
- NX_PTR_ERROR:(0x07) 套接字指针无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_NOT_ENABLED:(0x14) 此组件尚未启用。
- NX_UNDERFLOW:(0x02) 数据包前置指针无效。
注意事项:
- 除非返回了错误,否则应用程序不应在调用此函数后释放该数据包。这样做会导致不可预知的结果,因为网络驱动程序还会在传输后尝试释放该数据包。
使用举例:
代码语言:javascript复制/* 立即将接收到的数据发送回去 */
ret = nx_tcp_socket_send(&TCPSocket, /* TCP Socket控制块 */
data_packet, /* 数据包 */
NX_WAIT_FOREVER); /* 永久等待 */
9.2.13 函数nx_packet_data_retrieve
函数原型:
代码语言:javascript复制UINT nx_packet_data_retrieve(
NX_PACKET *packet_ptr,
VOID *buffer_start,
ULONG *bytes_copied);
函数描述:
此函数用于将提供的数据包中的数据复制到提供的缓冲区。复制的实际字节数由形参bytes_copied 所指向的存储单元返回。
注意,此函数不会更改该数据包的内部状态。检索的数据仍存在于该数据包中。
函数参数:
1、 第1个参数是指向源数据包的指针
2、 第2个参数是目的数据包的地址。
3、 第3个参数是最终复制的字节数存储地址。
4、 返回值,返回以下几种状态值:
- NX_SUCCESS:(0x00)复制数据包数据成功。
- NX_INVALID_PACKET:(0x12) 数据包无效。
- NX_PTR_ERROR:(0x07) 形参地址无效。
注意事项:
目标缓冲区的大小必须足以容纳该数据包的内容。否则内存会损坏,导致不可预知的结果。
使用举例:
代码语言:javascript复制/* 获取客户端发来的数据 */
nx_packet_data_retrieve(data_packet, /* 接收到的数据包 */
data_buffer, /* 解析出数据 */
&bytes_read); /* 数据大小 */
9.2.14 函数nx_packet_release
函数原型:
UINT nx_packet_release(NX_PACKET *packet_ptr);
函数描述:
此函数用于释放数据包,包括链接到指定数据包的任何其他数据包。如果有其他任务在等待这个数据包,则该任务会获得该数据包并继续执行。
函数参数:
1、 第1个参数是数据包地址。
2、 返回值,返回以下几种状态值:
- NX_SUCCESS:(0x00) 释放数据包成功。
- NX_PTR_ERROR:(0x07) 数据包指针无效。
- NX_UNDERFLOW:(0x02) 预置指针小于有效负载开始位置。
- NX_OVERFLOW:(0x03) 追加指针大于有效负载结束位置。
注意事项:
应用程序必须防止多次释放同一数据包,否则会导致不可预知的结果。
9.2.15 函数nx_tcp_socket_disconnect
函数原型:
代码语言:javascript复制UINT nx_tcp_socket_disconnect(
NX_TCP_SOCKET *socket_ptr,
ULONG wait_option);
函数描述:
此函数用于断开已建立的客户端或服务器Socket。在服务器Socket断开连接后应该有一个取消接受请求,而断开连接的客户端Socket会处于准备好接受其他连接请求的状态。 如果断开连接过程无法立即完成,则该函数会根据提供的等待选项挂起。
函数参数:
1、 第1个参数是TCP Socket地址。
2、 第2个参数等待断开连接时,支持的参数:
- NX_NO_WAIT (0x00000000)。
- NX_WAIT_FOREVER (0xFFFFFFFF)。
- 以时钟周期为单位的超时值(0x00000001 到 0xFFFFFFFE)。
3、 返回值,返回以下几种状态值:
- NX_SUCCESS:(0x00) 断开Socket连接成功。
- NX_NOT_CONNECTED:(0x38) 指定的Socket未连接。
- NX_IN_PROGRESS:(0x37) 断开连接正在进行。
- NX_WAIT_ABORTED:(0x1A) 已通过调用 tx_thread_wait_abort 中止挂起请求。
- NX_PTR_ERROR:(0x07) Socket指针无效。
- NX_CALLER_ERROR:(0x11) 此服务的调用方无效。
- NX_NOT_ENABLED:(0x14) 此组件尚未启用。
使用举例:
代码语言:javascript复制/* 断开连接 */
nx_tcp_socket_disconnect(&TCPSocket,
NX_WAIT_FOREVER);
9.3 TCP客户端的实现方法
9.3.1 NetXDUO初始化
创建TCP服务器前,要初始化NetX,创建内存池,例化IP:
代码语言:javascript复制/*
*********************************************************************************************************
* 函 数 名: NetXTest
* 功能说明: TCPnet应用
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void NetXTest(void)
{
UINT status;
UINT ret;
ULONG socket_state;
UINT old_priority;
NX_PACKET *data_packet;
ULONG bytes_read;
ULONG peer_ip_address;
ULONG peer_port;
/* 初始化NetX */
nx_system_initialize();
/* 创建内存池 */
status = nx_packet_pool_create(&pool_0, /* 内存池控制块 */
"NetX Main Packet Pool",/* 内存池名 */
1536, /* 内存池每个数据包大小,单位字节此值必须至少为 40 个字节,并且还必须可以被 4 整除 */
(ULONG*)(((int)packet_pool_area 15) & ~15) ,/* 内存池地址,此地址必须ULONG对齐 */
NX_PACKET_POOL_SIZE); /* 内存池大小 */
/* 检测创建是否失败 */
if (status) error_counter ;
/* 例化IP */
status = nx_ip_create(&ip_0, /* IP实例控制块 */
"NetX IP Instance 0", /* IP实例名 */
IP_ADDRESS(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3), /* IP地址 */
0xFFFFFF00UL, /* 子网掩码 */
&pool_0, /* 内存池 */
nx_driver_stm32h7xx, /* 网卡驱动 */
(UCHAR*)AppTaskNetXStk, /* IP任务栈地址 */
sizeof(AppTaskNetXStk), /* IP任务栈大小,单位字节 */
APP_CFG_TASK_NETX_PRIO); /* IP任务优先级 */
/* 检测创建是否失败 */
if (status) error_counter ;
/* 使能ARP,并提供ARP缓存 */
status = nx_arp_enable(&ip_0, /* IP实例控制块 */
(void *)arp_space_area, /* ARP缓存地址 */
sizeof(arp_space_area)); /* 每个 ARP 条目均为 52 个字节,因此,ARP 条目总数是52字节整数倍 */
/* 使能fragment */
status = nx_ip_fragment_enable(&ip_0);
/* 检测使能成功 */
if (status) error_counter ;
/* 使能TCP */
status = nx_tcp_enable(&ip_0);
/* 检测使能成功 */
if (status) error_counter ;
/* 使能UDP */
status = nx_udp_enable(&ip_0);
/* 检测使能成功 */
if (status) error_counter ;
/* 使能ICMP */
status = nx_icmp_enable(&ip_0);
/* 检测使能成功 */
if (status) error_counter ;
/* NETX初始化完毕后,重新设置优先级 */
tx_thread_priority_change(netx_thread_ptr, APP_CFG_TASK_NETX_PRIO1, &old_priority);
tx_thread_priority_change(&AppTaskNetXProTCB, APP_CFG_TASK_NetXPro_PRIO1, &old_priority);
/* 省略 */
}
程序末尾务优先级做了特别处理,创建的时候先设置为低优先级,检测到网线正常连接并初始了网络后将优先级设置到正常水平。
9.3.2 TCP客户端实现
下面是创建TCP客户端并远程连接服务器:
代码语言:javascript复制/*
*********************************************************************************************************
* 函 数 名: NetXTest
* 功能说明: TCPnet应用
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void NetXTest(void)
{
/* 省略 */
/* 创建TCP Socket */
ret = nx_tcp_socket_create(&ip_0, /* IP实例控制块 */
&TCPSocket, /* TCP控制块 */
"TCP Server Socket", /* TCP Socket名 */
NX_IP_NORMAL, /* IP服务类型 */
NX_FRAGMENT_OKAY, /* 使能IP分段 */
NX_IP_TIME_TO_LIVE, /*用于定义此数据包在被丢弃之前可通过的路由器数目 */
4320, /* TCP Socket接收队列中允许的最大字节数 */
NX_NULL, /* 用于在接收流中检测到紧急数据时调用的回调函数 */
NX_NULL); /* TCP Socket另一端发出断开连接时调用的回调函数 */
if (ret)
{
Error_Handler(__FILE__, __LINE__);
}
/*
* 监听新的链接。
* 创建回调TCP_listen_callback表示监听到新连接。
*/
ret = nx_tcp_server_socket_listen(&ip_0, /* IP实例控制块 */
DEFAULT_PORT, /* 默认端口 */
&TCPSocket, /* TCP Socket控制块 */
MAX_TCP_CLIENTS, /* 可以监听的连接数 */
NULL); /* 监听回调函数 */
if (ret)
{
Error_Handler(__FILE__, __LINE__);
}
/* 启动TCP通信前,接收新连接 */
ret = nx_tcp_server_socket_accept(&TCPSocket, /* TCP Socket控制块 */
TX_WAIT_FOREVER); /* 监听回调函数 */
if (ret)
{
Error_Handler(__FILE__, __LINE__);
}
/* 绑定端口 */
ret = nx_tcp_client_socket_bind(&TCPSocket, DEFAULT_PORT, NX_WAIT_FOREVER);
if (ret != NX_SUCCESS)
{
Error_Handler(__FILE__, __LINE__);
}
/* 连接远程服务器 */
ret = nx_tcp_client_socket_connect(&TCPSocket, TCP_SERVER_ADDRESS, TCP_SERVER_PORT, NX_WAIT_FOREVER);
if (ret != NX_SUCCESS)
{
Error_Handler(__FILE__, __LINE__);
}
/* 省略 */
}
9.3.3 TCP回环通信实现
回环的意思就是电脑端网络助手发送数据给板子后,板子再将数据返回。为了方便大家使用,本例子将接收数据包和发送数据包分别做了定义:
代码语言:javascript复制/*
*********************************************************************************************************
* 函 数 名: NetXTest
* 功能说明: TCPnet应用
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void NetXTest(void)
{
/* 省略 */
while(1)
{
TX_MEMSET(data_buffer, '