前言
- 本篇需要用到threadx之动态内存的实现记录 里面的动态内存分配管理代码.
- 开发环境使用的stm32cubemx+clion组合
- 芯片使用的是stm32f407zgt6,网口使用的是lan8720,使用cubemx提供的lan8742也可以驱动,注意实际的网口与芯片的引脚
示例代码
tcp 服务端
/** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-4-8 shchl first version*/
#include "includes.h"
#include "nx_tcp.h"#define TCP_SERVER_STACK_SIZE 4096 /*任务栈大小*/
#define TCP_SERVER_PRIORITY 4 /*优先级*/
#define PACKET_SIZE 1536 /*数据包大小*/
#define POOL_SIZE ((sizeof(NX_PACKET) + PACKET_SIZE) * 16) /*数据包池大小(16个缓冲区)*/
#define TCP_SERVER_IP IP_ADDRESS(192, 168, 8, 9) /*本地ip*/
#define TCP_SERVER_LISTEN_PORT 8080 /*监听端口*/
TX_THREAD tcp_server_thread; /*tcp 服务线程*/
NX_PACKET_POOL tcp_server_pool; /*数据包池*/
NX_IP tcp_server_ip; /*服务端ip,即本地ip*/
NX_TCP_SOCKET tcp_server_socket; /*服务端socket*/
static ULONG error_counter = 0; /*错误计数器(可用来排查问题出现位置)*/VOID thread_server_entry(ULONG thread_input);void tcp_server_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port);void tcp_server_disconnect_received_callback(NX_TCP_SOCKET *socket);static UINT receive_socket_handle(NX_TCP_SOCKET *socket);static inline void status_check(UINT stat) {if (stat) {error_counter++;// todo }
}
/*** @brief tcp 服务线程创建*/
void app_task_tcp_server_thread_create() {tx_log("------------------app_task_tcp_server_thread_create start--------------------\r\n");UINT status;/* 创建server 线程. */tx_thread_create(&tcp_server_thread,"tcp sever thread",thread_server_entry, 0,app_malloc(TCP_SERVER_STACK_SIZE),TCP_SERVER_STACK_SIZE,TCP_SERVER_PRIORITY,TCP_SERVER_PRIORITY,TX_NO_TIME_SLICE,TX_AUTO_START);/* 创建 packet 内存池(可以理解为分配一个大数组). */status = nx_packet_pool_create(&tcp_server_pool,"server packet pool",PACKET_SIZE,app_malloc(POOL_SIZE),POOL_SIZE);status_check(status);/* 创建一个ip 实列. 内部会创建一个对应的线程 */status = nx_ip_create(&tcp_server_ip,"tcp server instance",TCP_SERVER_IP, 0xFFFFFF00UL, &tcp_server_pool,nx_stm32_eth_driver,/*对应的网卡驱动*/app_malloc(2048), /*ip 内存栈空间首地址*/2048,2);status_check(status);/* 开启 地址解析协议 并分配缓冲区. */status = nx_arp_enable(&tcp_server_ip, app_malloc(1024), 1024);status_check(status);/*开启 icmp 协议, 能通过ping 命令去检查ip */status = nxd_icmp_enable(&tcp_server_ip);status_check(status);/* 开启 tcp 处理 */status = nx_tcp_enable(&tcp_server_ip);tx_log("------------------app_task_tcp_server_thread_create finished--------------------\r\n");}VOID thread_server_entry(ULONG thread_input) {NX_PARAMETER_NOT_USED(thread_input);UINT status;ULONG actual_status;/* 确保 IP 实例已初始化。 */do {/* 等待 1 秒钟,让 内部 IP 线程完成其初始化。. */status = nx_ip_status_check(&tcp_server_ip,NX_IP_INITIALIZE_DONE,&actual_status,NX_IP_PERIODIC_RATE);} while (status != NX_SUCCESS);/* 创建socket */status = nx_tcp_socket_create(&tcp_server_ip,&tcp_server_socket,"Server Socket",NX_IP_NORMAL, /* IP服务类型 */NX_FRAGMENT_OKAY,/* 使能IP分段 */NX_IP_TIME_TO_LIVE, /*默认数据包生存时间*/PACKET_SIZE, /*这个参数对应到后面发送的数据包是否会进行分包处理*/NX_NULL, /* 用于在接收流中检测到紧急数据时调用的回调函数 */tcp_server_disconnect_received_callback /* TCP Socket另一端发出断开连接时调用的回调函数 */);status_check(status);/* 监听新的链接。 */status = nx_tcp_server_socket_listen(&tcp_server_ip, /* IP实例控制块 */TCP_SERVER_LISTEN_PORT, /* 端口 */&tcp_server_socket,/* TCP Socket控制块 */5,/* 可以监听的连接数 */tcp_server_connect_received /* 监听接收到连接函数 */);status_check(status);while (1) {/* 接受客户端套接字连接。(阻塞) */status = nx_tcp_server_socket_accept(&tcp_server_socket, NX_WAIT_FOREVER);status_check(status);/*处理接收到的客户端连接*/receive_socket_handle(&tcp_server_socket);/* 断开服务器套接字。 */status = nx_tcp_socket_disconnect(&tcp_server_socket, NX_IP_PERIODIC_RATE);if (status) {error_counter++;}/* 解除Socket和服务器端口的绑定 */status = nx_tcp_server_socket_unaccept(&tcp_server_socket);status_check(status);/* 重新监听 */status = nx_tcp_server_socket_relisten(&tcp_server_ip,TCP_SERVER_LISTEN_PORT,&tcp_server_socket);status_check(status);}}void tcp_server_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port) {/* Check for the proper socket and port. */if ((socket_ptr != &tcp_server_socket) || (port != TCP_SERVER_LISTEN_PORT)) {error_counter++;} else {ULONG ipaddr = socket_ptr->nx_tcp_socket_connect_ip.nxd_ip_address.v4;tx_log("current ip: %lu.%lu.%lu.%lu:%d\r\n",(ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff,(ipaddr >> 8) & 0xff, (ipaddr & 0xff), socket_ptr->nx_tcp_socket_port);}
}void tcp_server_disconnect_received_callback(NX_TCP_SOCKET *socket) {/* Check for proper disconnected socket. */if (socket != &tcp_server_socket) {error_counter++;}
}/*** @brief 处理接收的socket* @param socket* @return*/
static UINT receive_socket_handle(NX_TCP_SOCKET *socket) {UINT status;NX_PACKET *packet_ptr;continue_rec:/* Receive a TCP message from the socket. */status = nx_tcp_socket_receive(&tcp_server_socket, &packet_ptr, NX_IP_PERIODIC_RATE);/* Check for error. */switch (status) {case NX_SUCCESS: {*packet_ptr->nx_packet_append_ptr = '\0'; /*在结尾处添加结束标志位,这里可以这样处理,前提是确保指向的位置可以被修改*/tx_log("data packet size:%d\r\n", packet_ptr->nx_packet_length);tx_log("nx_tcp_socket_receive data:%s\r\n", packet_ptr->nx_packet_prepend_ptr);/*处理完成之后释放数据包,这里需要我们自己进行释放*/nx_packet_release(packet_ptr);goto continue_rec; /*继续接收客户端*/}case NX_NO_PACKET: { /*客户端连接,但没有发送数据,这里可以做超时断开客户端连接操作*/// tx_log("nx_tcp_socket_receive NX_NO_PACKET\r\n");goto continue_rec; /*继续接收客户端*/}case NX_NOT_CONNECTED: {tx_log("client disconnected\r\n");break;}default: {tx_log("nx_tcp_socket_receive status:%d\r\n", status);break;}}return NX_SUCCESS;
}
调用主逻辑
结果