1回答

0收藏

[评测分享] 【更适合初学者的开发板ELF 1】13-多线程测试-TCPServer

#板卡评测 #板卡评测 1821 人阅读 | 1 人回复 | 2023-12-09

本帖最后由 stm1024 于 2023-12-9 22:03 编辑

0. 前言
前面测试过UDP和TCP的程序,显示功能正常,但是测试程序中都是单点之间的通讯,而且服务端和客户端,要有严格的顺序,并且,客户端或者服务端挂掉以后,另一边也会受到影响。此外,实际使用的时候可能有多个客户端连接服务端,此时我们可以考虑使用多进程或者多线程,但是使用多进程的话,占用的资源比较多,这个对一般的入门级嵌入式linux处理器不太友好,此外,还有可能会带来IPC(进程间通讯)的工作,因此,常见的嵌入式环境下,使用的是单进程+多线程,而不是多线程+单进程。

1. 编程规划
前面已经编写过了TCP的服务器端程序和客户端程序。本次重新改写TCP服务器端程序,测试多个客户端的连接。

2. 程序代码
完整的服务端测试代码如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <unistd.h>
  6. #include <arpa/inet.h>
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <ctype.h>
  10. #include <signal.h>
  11. #include <pthread.h>

  12. #define SERVER_PORT 12345
  13. #define BUF_LEN 1024
  14. #define THREAD_NUM 10
  15. void dispErrInfo(const char* pretext,int errcode)
  16. {
  17.     printf("%s, errno=%d: %s\n",pretext,errcode,strerror(errcode));
  18. }

  19. void *child(void *arg)
  20. {
  21.     int i, rcvlen,ret,socketfd;
  22.     i=0;
  23.     rcvlen=-1;
  24.     ret=-1;
  25.     socketfd=*(int*)arg;
  26.     char buf[BUF_LEN];
  27.     memset(buf,0x00,256);

  28.     pthread_t tid=pthread_self();
  29.     printf("[THREAD %lu] ENTER.\n",tid);

  30.     if((rcvlen=recv(socketfd,buf,BUF_LEN,0))==-1)
  31.     {
  32.         close(socketfd);
  33.         dispErrInfo("[THREAD %lu] ERROR.\n",errno);
  34.         exit(EXIT_FAILURE);
  35.     }

  36.     printf("[THREAD %lu] Received From Client:%s.\n",tid,buf);

  37.     //process
  38.     for(i=0;i<rcvlen;i++)
  39.         buf[i]=toupper(buf[i]);
  40.     //send back
  41.     if(send(socketfd,buf,rcvlen,0)==-1)
  42.     {
  43.         close(socketfd);
  44.         dispErrInfo("[THREAD %lu] ERROR.\n",errno);
  45.         exit(EXIT_FAILURE);
  46.     }
  47.     printf("[THREAD %lu] EXIT.\n",tid);
  48.     close(socketfd);
  49.     pthread_exit(NULL);
  50. }


  51. int main(int argc, char** argv)
  52. {      
  53.     int socket_desc;
  54.     int temp_socket_desc[THREAD_NUM];
  55.     int t_num=0;   
  56.     int address_size;   
  57.    
  58.     struct sockaddr_in sin;
  59.     bzero(&sin,sizeof(sin));
  60.     sin.sin_family = AF_INET;
  61.     sin.sin_addr.s_addr = INADDR_ANY;                                 
  62.     sin.sin_port = htons(SERVER_PORT);

  63.     signal(SIGPIPE, SIG_IGN);
  64.                  
  65.     if((socket_desc = socket(AF_INET,SOCK_STREAM,0)) == -1)
  66.     {
  67.         dispErrInfo("Error open socket.\n",errno);
  68.         exit(EXIT_FAILURE);
  69.     }
  70.          
  71.     if(bind(socket_desc,(struct sockaddr *)&sin,sizeof(sin)) ==-1)
  72.     {
  73.         dispErrInfo("Error bind socket.\n",errno);
  74.         exit(EXIT_FAILURE);
  75.     }
  76.     if(listen(socket_desc,20) == -1)
  77.     {
  78.         dispErrInfo("Error listen socket.\n",errno);
  79.         exit(EXIT_FAILURE);
  80.     }
  81.     printf("Waiting connect...\n");
  82.     pthread_attr_t attr;
  83.         pthread_attr_init(&attr);
  84.     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  85.     while(1)
  86.     {         
  87.          pthread_t tid;
  88.         temp_socket_desc[t_num] = accept(socket_desc,NULL, NULL);
  89.         if(temp_socket_desc[t_num] == -1)
  90.         {
  91.            dispErrInfo("Error accept socket.\n",errno);
  92.            break;
  93.         }        
  94.          printf("create thread.\n");
  95.          if (pthread_create(&tid,&attr,child,&temp_socket_desc[t_num]) == -1)
  96.         {
  97.                    dispErrInfo("Error create thread.\n",errno);
  98.                     break;
  99.                   }        
  100.                   t_num = t_num+1;
  101.                   if(t_num >= THREAD_NUM)        
  102.                   {
  103.                           break;
  104.                   }                                
  105.     }
  106.         pthread_attr_destroy(&attr);
  107.     return (EXIT_SUCCESS);
  108. }
复制代码

3. 测试效果
编译,注意我们使用了多线程技术,因此在虚拟机中编译的时候,需要加入 -lpthread,如下:

上图中,agcc是我对/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/agcc做的link。

然后就是常规的拷贝到开发板中,赋予可执行权限等操作,最后运行。
在Windows主机上打开三个网络调试助手,以TCP客户端形式工作,连接服务端:
可见开发板上的程序可以正常收到各服务端发送的数据:


OK,今天测试就到这里。
分享到:
回复

使用道具 举报

回答|共 1 个

倒序浏览

沙发

xiaoshen-372360

发表于 2023-12-11 15:51:14 | 只看该作者

支持一下大佬,向大佬看齐。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

5300 积分
55 主题
+ 关注
热门推荐
关闭

站长推荐上一条 /3 下一条