好记性不如烂笔头,既然不够聪明,就乖乖的做笔记,温故而知新。
本文档用于本人对知识点的梳理和记录
AT32F437 UCOSIII系统Lwip下NETCONN编程接口TCP多客户端连接
一、目录
AT32F437 UCOSIII系统Lwip下NETCONN编程接口TCP多客户端连接
二、硬件工具
开发板:AT-START-F437
路由器:MERCURY一台
辅助材料:网线若干
软件工具:KEIL,VS Vode,网络调试助手PC版和Android版
三、添加TCP多客户端过程
3.1 创建连接管理任务、数据处理任务
sys_thread_new("tcp_handle", svr_task, NULL, ECHO_STK_SIZE, ECHO_THREAD_PRIO );
sys_thread_new("tcp_server_thread", tcp_server_thread, NULL, ECHO_STK_SIZE, ECHO_THREAD_PRIO );
3.2 svr_task任务,用于轮询建立TCP连接,conn->acceptmbox.Type = OS_OBJ_TYPE_Q;非常重要,如果不添加,可能会导致netconn_accept和netconn_delete函数进入while等待邮箱数据。client_init函数用于管理和分配多路TCP连接。
void svr_task(void *arg)
{
OS_ERR oserr; //错误标志(UCOSIII)
conn = netconn_new(NETCONN_TCP); //创建一个TCP服务器连接
netconn_bind(conn,IP_ADDR_ANY,TCP_PORT); //绑定端口号
netconn_listen(conn); //进入监听模式
printf("accepted new connection %p\n", newconn);
/* Process the new connection. */
newconn = NULL;
while(1)
{
if(newconn->state != NETCONN_NONE)
{
conn->acceptmbox.Type = OS_OBJ_TYPE_Q; //非常重要,必须添加
if(netconn_accept(conn, &newconn) == ERR_OK) //接收到正确的连接请求
{
newconn->recv_timeout = 200; //禁止阻塞线程 等待200ms
if(client_init((void *)newconn) != ERR_OK) //判断 TCP 客户端任务是否创建成功
{ //若创建失败
netconn_close(newconn); //关闭 TCP client 连接
netconn_delete(newconn); //删除 TCP client 连接
}
newconn = NULL; //连接后复位newconn
}
newconn->acceptmbox.Type = OS_OBJ_TYPE_Q; //非常重要,必须添加
}
OSTimeDly(300, OS_OPT_TIME_DLY, &oserr);
}
}
3.3 数据处理任务中轮询接收有数据到来的TCP链路并将数据回传到对应的TCP Client。如果检测TCP 断开,将删除对应的设备信息,确保下一次连接无误。
static void tcp_server_thread(void *arg)
{
OS_ERR oserr;
err_t recv_err;
void* tx_buf;
u16_t tx_len=0;
uint8_t client = 0;
struct netbuf *recvbuf;
while(1)
{
if(client < CLIENTMAX){
if(clientad.num_max != 0){
for(client=0;client < clientad.num_max;client++){
if(clientad.state[client]==1)
{
if((recv_err = netconn_recv(clientad.conn[client],&recvbuf)) == ERR_OK) //接收到数据
{
tx_buf = recvbuf->p->payload;
tx_len = recvbuf->p->len;
netconn_write(clientad.conn[client], tx_buf, tx_len, NETCONN_COPY); //接收到的数据发送回去
netbuf_delete(recvbuf);
printf("rev %d data success!\n",client);
}
else if(recv_err == ERR_CLSD||recv_err==ERR_RST) //关闭连接或复位数据
{
client_count--;
netconn_close(clientad.conn[client]);
clientad.conn[client]->acceptmbox.Type = OS_OBJ_TYPE_Q; //非常重要,必须添加
netconn_delete(clientad.conn[client]); //删除连接
clientad.state[client]=0; //第 client->num_max 个设备状态置0 表示客户端已断开
clientad.num_max--;
printf("link close!\n");
}
}
}
if(client >= clientad.num_max)
client=0;
}
}
OSTimeDly(10, OS_OPT_TIME_DLY, &oserr);
}
}
3.4 相关定义
#define CLIENTMAX 10 //最大客户端连接数量
//客户端地址结构体
typedef struct client_ad_t
{
struct netconn *conn[CLIENTMAX];
uint8_t num[CLIENTMAX]; //客户端连接地址保存(最多20个客户端连接 地址全存这里了)
uint8_t num_max; //客户端已连接设备的数量
uint8_t state[CLIENTMAX]; //客户端连接状态
}client_ad;
client_ad clientad; //TCP客户端地址结构体(全局变量)
四、总结
conn->acceptmbox.Type = OS_OBJ_TYPE_Q;非常重要!