rt-thread tcp服务器 多客户端连接

1 tcp 服务端测试

我们从rt-thread 源码中的example 文件夹可以找到一个名为tcpserver.c 的文件, 我们按照官网说明, 添加此文件拖进项目中去, 即可实现tcpserver 测试功能. 参考链接 : stm32f429网络功能配置
或者使用env 工具,添加tcp 服务器测试代码到工程中去
(需要先配置好网络功能, 打开lwip sal 等驱动及其软件包, 具体操作参看board.h 或者官方文档)rt-thread tcp服务器 多客户端连接_第1张图片
添加好tcpserver.c 后, 使用 tcpserver -p 8000 即可开启tcp 服务端, 在测试的过程中发现, 此测试程序仅仅支持单连接, 实际使用中可能会遇到多连接的情况, 所以我通过阅读测试代码发现, 只需要建立连接后,创建一个单独的线程, 用来处理处理不同的客户端即可.

2 tcp 客户端多线程创建

在使用accept 函数后, 可以堵塞等待获取一个客户端连接, 得到连接后的sock 后, 立即创建一个线程, 我在线程传入参数使用了两个参数, 1 客户端序号 0 -8 (设置了最大8个连接), 2 sock 号

void tcp__init(int sock )
{
   rt_thread_t tid;
     char name[10]; 
     struct tcp_c_s *parm = rt_malloc(sizeof(struct tcp_c_s));
     parm->num = g_cnt; // 客户端编号
     parm->sock = sock; // 客户端sock 
   
     if(g_cnt < MAX_CLIENT)
   	{
     rt_sprintf(name,"tcp_%d",g_cnt); 
     tid = rt_thread_create(name, tcp__thread_entry, parm, TCP__THREAD_STACK_SIZE, TCP__THREAD_PRIORITY, TCP__THREAD_TIME);
     if (tid != RT_NULL)
     {
       rt_thread_startup(tid);
     }
     else
     {
       rt_kprintf("tcp_ thread create failed");
     }
   		g_cnt ++; 
     }
   	else
   	{
   	 rt_kprintf("client is too more\r\n");
   	
   	}
}

每次收到一次连接后, 都会创建一个线程, 用来处理当前客户端连接的传输数据
线程的具体内容, 只需要把官方测试代码的while(1) 部分 全盘复制过去即可

2.1 线程循环体

/* 每一个客户端连接线程入口函数 */
static void tcp__thread_entry(void *parameter) //每连接一个创建一个子进程 
{
   struct tcp_c_s *p = (struct tcp_c_s *)parameter;
   struct tcp_c_s tcp_m  ; // 获取当前sock
   tcp_m.num = p->num;
   tcp_m.sock = p->sock; 
   
   int sock = tcp_m.sock; // 获取当前sock 
   //uint8_t num = *num_p;
    fd_set readset, readset_c;
   uint8_t ret; 
   uint8_t *recv_data = rt_malloc(BUFSZ);
   uint16_t bytes_received; 
   struct timeval timeout;
   
     timeout.tv_sec = 3;
   timeout.tv_usec = 0;
   
     rt_kprintf("thread %d, sock %d",tcp_m.num,tcp_m.sock);
    while (1)
       {
   				
           FD_ZERO(&readset_c);
           FD_SET(sock, &readset_c);

           /* Wait for read or write */
           if (select(sock + 1, &readset_c, RT_NULL, RT_NULL, &timeout) == 0)
               continue;

           /* 从connected socket中接收数据,接收buffer是1024大小,但并不一定能够收到1024大小的数据 */
           bytes_received = recv(sock, recv_data, BUFSZ, 0);
           if (bytes_received < 0)
           {
               LOG_E("Received error, close the connect.");
               closesocket(sock);
               sock = -1;
               break;
           }
           else if (bytes_received == 0)
           {
               /* 打印recv函数返回值为0的警告信息 */
               LOG_W("Received warning, recv function return 0.");
               continue;
           }
           else
           {
               /* 有接收到数据,把末端清零 */
               recv_data[bytes_received] = '\0';
               if (strcmp((char *)recv_data, "q") == 0 || strcmp((char *)recv_data, "Q") == 0)
               {
                   /* 如果是首字母是q或Q,关闭这个连接 */
                   LOG_I("Got a 'q' or 'Q', close the connect.");
                   closesocket(sock);
                   sock = -1;
                   break;
               }
               else if (strcmp((char *)recv_data, "exit") == 0)
               {
                   /* 如果接收的是exit,则关闭整个服务端 */
                   closesocket(sock);
                   sock = -1;
                  // goto __exit;
               }
               else
               {
                   /* 在控制终端显示收到的数据 */
   								LOG_D("%d :Received data = %s",tcp_m.num, recv_data);
               }
           }

           /* 发送数据到connected socket */
           ret = send(sock, send_data, rt_strlen(send_data), 0);
           if (ret < 0)
           {
               LOG_E("send error, close the connect.");
               closesocket(sock);
               sock = -1;
               break;
           }
           else if (ret == 0)
           {
               /* 打印send函数返回值为0的警告信息 */
               LOG_W("Send warning, send function return 0.");
           }
       }
   			rt_free(parameter);
}

3 测试

创建线程后, 经过测试, 可以实现多客户端
rt-thread tcp服务器 多客户端连接_第2张图片
6个箭头分别对应 3个客户端连接, 和3个客户端发送的数据

rt-thread tcp服务器 多客户端连接_第3张图片
这是开启了三个tcp 客户端连接单片机上的tcp 服务器

4 遗留的问题和隐患

4.1内存使用

通过创建线程实现了多客户端连接, 但是存在内存使用过大, 每个连接需要创建一个线程, 线程栈大小1KB , 需要创建一个数据接收缓冲区, 目前也是1KB , 如果8个客户端全连, 就需要至少8KB 的额外ram , 可以通过修改最大数目客户端连接个数限制.

4.1 下线检测

原来的测试程序中没有断线检测, 回收资源的操作, 目前也没有进行添加, 如需要稳定运行, 需要考虑进去, 回收线程资源, 关闭已经下线的 socket
这个功能未来我可能会优化一下, 有兴趣的小伙伴可以帮忙提交一下方案

代码链接 : 测试代码

你可能感兴趣的:(rtt,网络)