TA的每日心情  | 慵懒 2025-8-6 21:07 | 
|---|
 
  签到天数: 313 天 连续签到: 1 天 [LV.8]以坛为家I 
状元 
 
 
	- 积分
 - 5300
 
 
 
 
 | 
 
 
 本帖最后由 stm1024 于 2023-12-9 22:03 编辑  
 
0. 前言 
前面测试过UDP和TCP的程序,显示功能正常,但是测试程序中都是单点之间的通讯,而且服务端和客户端,要有严格的顺序,并且,客户端或者服务端挂掉以后,另一边也会受到影响。此外,实际使用的时候可能有多个客户端连接服务端,此时我们可以考虑使用多进程或者多线程,但是使用多进程的话,占用的资源比较多,这个对一般的入门级嵌入式linux处理器不太友好,此外,还有可能会带来IPC(进程间通讯)的工作,因此,常见的嵌入式环境下,使用的是单进程+多线程,而不是多线程+单进程。 
 
1. 编程规划 
前面已经编写过了TCP的服务器端程序和客户端程序。本次重新改写TCP服务器端程序,测试多个客户端的连接。 
 
2. 程序代码 
完整的服务端测试代码如下: 
- #include <stdio.h>
 
 - #include <stdlib.h>
 
 - #include <string.h>
 
 - #include <errno.h>
 
 - #include <unistd.h>
 
 - #include <arpa/inet.h>
 
 - #include <sys/types.h>
 
 - #include <sys/socket.h>
 
 - #include <ctype.h>
 
 - #include <signal.h>
 
 - #include <pthread.h>
 
  
- #define SERVER_PORT 12345
 
 - #define BUF_LEN 1024
 
 - #define THREAD_NUM 10
 
 - void dispErrInfo(const char* pretext,int errcode)
 
 - {
 
 -     printf("%s, errno=%d: %s\n",pretext,errcode,strerror(errcode));
 
 - }
 
  
- void *child(void *arg)
 
 - {
 
 -     int i, rcvlen,ret,socketfd;
 
 -     i=0;
 
 -     rcvlen=-1;
 
 -     ret=-1;
 
 -     socketfd=*(int*)arg;
 
 -     char buf[BUF_LEN];
 
 -     memset(buf,0x00,256);
 
  
-     pthread_t tid=pthread_self();
 
 -     printf("[THREAD %lu] ENTER.\n",tid);
 
  
-     if((rcvlen=recv(socketfd,buf,BUF_LEN,0))==-1)
 
 -     {
 
 -         close(socketfd);
 
 -         dispErrInfo("[THREAD %lu] ERROR.\n",errno);
 
 -         exit(EXIT_FAILURE);
 
 -     }
 
  
-     printf("[THREAD %lu] Received From Client:%s.\n",tid,buf);
 
  
-     //process
 
 -     for(i=0;i<rcvlen;i++)
 
 -         buf[i]=toupper(buf[i]);
 
 -     //send back
 
 -     if(send(socketfd,buf,rcvlen,0)==-1)
 
 -     {
 
 -         close(socketfd);
 
 -         dispErrInfo("[THREAD %lu] ERROR.\n",errno);
 
 -         exit(EXIT_FAILURE);
 
 -     }
 
 -     printf("[THREAD %lu] EXIT.\n",tid);
 
 -     close(socketfd);
 
 -     pthread_exit(NULL);
 
 - }
 
  
 
- int main(int argc, char** argv) 
 
 - {      
 
 -     int socket_desc;
 
 -     int temp_socket_desc[THREAD_NUM];
 
 -     int t_num=0;    
 
 -     int address_size;   
 
 -     
 
 -     struct sockaddr_in sin;
 
 -     bzero(&sin,sizeof(sin));
 
 -     sin.sin_family = AF_INET;
 
 -     sin.sin_addr.s_addr = INADDR_ANY;                                 
 
 -     sin.sin_port = htons(SERVER_PORT); 
 
 -  
 
 -     signal(SIGPIPE, SIG_IGN);
 
 -                  
 
 -     if((socket_desc = socket(AF_INET,SOCK_STREAM,0)) == -1)
 
 -     {
 
 -         dispErrInfo("Error open socket.\n",errno);
 
 -         exit(EXIT_FAILURE);
 
 -     }
 
 -          
 
 -     if(bind(socket_desc,(struct sockaddr *)&sin,sizeof(sin)) ==-1)
 
 -     {
 
 -         dispErrInfo("Error bind socket.\n",errno);
 
 -         exit(EXIT_FAILURE);
 
 -     }
 
 -     if(listen(socket_desc,20) == -1)
 
 -     {
 
 -         dispErrInfo("Error listen socket.\n",errno);
 
 -         exit(EXIT_FAILURE);
 
 -     }
 
 -     printf("Waiting connect...\n");
 
 -     pthread_attr_t attr;
 
 -         pthread_attr_init(&attr);
 
 -     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 
 
 -     while(1)
 
 -     {          
 
 -          pthread_t tid;
 
 -         temp_socket_desc[t_num] = accept(socket_desc,NULL, NULL);
 
 -         if(temp_socket_desc[t_num] == -1)
 
 -         {
 
 -            dispErrInfo("Error accept socket.\n",errno);
 
 -            break;
 
 -         }        
 
 -          printf("create thread.\n");
 
 -          if (pthread_create(&tid,&attr,child,&temp_socket_desc[t_num]) == -1) 
 
 -         {
 
 -                    dispErrInfo("Error create thread.\n",errno);
 
 -                     break;
 
 -                   }        
 
 -                   t_num = t_num+1;
 
 -                   if(t_num >= THREAD_NUM)        
 
 -                   {
 
 -                           break;
 
 -                   }                                
 
 -     }
 
 -         pthread_attr_destroy(&attr);
 
 -     return (EXIT_SUCCESS);
 
 - }
 
  复制代码 
3. 测试效果 
编译,注意我们使用了多线程技术,因此在虚拟机中编译的时候,需要加入 -lpthread,如下: 
 
上图中,agcc是我对/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/agcc做的link。 
 
然后就是常规的拷贝到开发板中,赋予可执行权限等操作,最后运行。 
在Windows主机上打开三个网络调试助手,以TCP客户端形式工作,连接服务端: 
可见开发板上的程序可以正常收到各服务端发送的数据: 
 
 
OK,今天测试就到这里。 
 |   
 
  
  
  
 
 
 |