查看: 1313|回复: 1

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

[复制链接]
  • TA的每日心情
    慵懒
    前天 10:54
  • 签到天数: 186 天

    连续签到: 2 天

    [LV.7]常住居民III

    发表于 2023-12-9 11:56:37 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 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,如下:
    0.png
    上图中,agcc是我对/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/agcc做的link。

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

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

    使用道具 举报

  • TA的每日心情
    开心
    2024-8-5 17:13
  • 签到天数: 333 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2023-12-11 15:51:14 | 显示全部楼层
    支持一下大佬,向大佬看齐。
    回复 支持 反对

    使用道具 举报

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

    本版积分规则

    关闭

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

    手机版|小黑屋|与非网

    GMT+8, 2024-12-24 07:53 , Processed in 0.124584 second(s), 19 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.