stm32开发之threadx+netxduo(tcp 服务端使用记录)
前言
- 本篇需要用到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;
}
调用主逻辑
结果
发送超过数据包大小
wireshark 数据查看
原文地址:https://blog.csdn.net/weixin_44742767/article/details/137546663
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!