IT评测·应用市场-qidao123.com

标题: Linux网络编程:socket & pthread_create()多线程 实现clients/server通信 [打印本页]

作者: 缠丝猫    时间: 2023-5-19 10:52
标题: Linux网络编程:socket & pthread_create()多线程 实现clients/server通信
一、问题引入

Linux网络编程:socket & fork()多进程 实现clients/server通信 随笔介绍了通过fork()多进程实现了服务器与多客户端通信。但除了多进程能实现之外,多线程也是一种实现方式。
重要的是,多进程和多线程是涉及操作系统层次。随笔不仅要利用pthread_create()实现多线程编程,也要理解线程和进程的区别。
二、解决过程

client 代码无需修改,请参考 Linux网络编程:socket & fork()多进程 实现clients/server通信
2-1 server 代码
  1. #include <stdlib.h>
  2. #include <pthread.h>
  3. #include <sys/socket.h>
  4. #include <sys/types.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <ctype.h>
  12. #include <sys/syscall.h>
  13. #define IP "10.8.198.227"
  14. #define PORT 8887
  15. #define gettid() syscall(__NR_gettid)
  16. #define PTHREAD_MAX_SIZE 3    // 允许最大客户端连接数
  17. typedef struct PTHREAD_DATA_ST
  18. {
  19.     pthread_t pthread_id;
  20.     int connfd;
  21.     char socket[128];
  22.     struct sockaddr_in cliaddr;
  23. }PTHREAD_DATA_ST;
  24. //static int g_pthread_num = 3; // 允许最大客户端连接数
  25. static struct PTHREAD_DATA_ST g_pthread_data[PTHREAD_MAX_SIZE];
  26. static void pthread_data_index_init(void)
  27. {
  28.     for (int i = 0; i < PTHREAD_MAX_SIZE; i++)
  29.     {
  30.         memset(&g_pthread_data[i], 0 , sizeof(struct PTHREAD_DATA_ST));
  31.         g_pthread_data[i].connfd = -1;
  32.     }
  33. }
  34. static int pthread_data_index_find(void)
  35. {
  36.     int i;
  37.     for (i = 0; i < PTHREAD_MAX_SIZE; i++)
  38.     {
  39.         if (g_pthread_data[i].connfd == -1)
  40.             break;
  41.     }
  42.     return i;
  43. }
  44. static int string_toupper(const char *src, int str_len, char *dst)
  45. {
  46.     int count = 0;
  47.     for (int i = 0; i < str_len; i++)
  48.     {
  49.         dst[i] = toupper(src[i]);
  50.         count++;
  51.     }
  52.     return count;
  53. }
  54. void *pthread_handle(void *arg)
  55. {
  56.     struct PTHREAD_DATA_ST *pthread = (struct PTHREAD_DATA_ST *)arg;
  57.     int connfd = pthread->connfd;
  58.     int recv_len, send_len;
  59.     pid_t tid = gettid();
  60.     char read_buf[1024], write_buf[1024];
  61.     while (1)
  62.     {
  63.         memset(read_buf, 0, sizeof(read_buf));
  64.         memset(write_buf, 0, sizeof(write_buf));
  65.         recv_len = read(connfd, read_buf, sizeof(read_buf));
  66.         if (recv_len <= 0)
  67.         {
  68.             printf("%s close, child %d terminated\n", pthread->socket, tid);
  69.             close(connfd);
  70.             pthread->connfd = -1;
  71.             pthread_exit(NULL);
  72.         }
  73.         printf("%s:%s(%d Byte)\n", pthread->socket, read_buf, recv_len);
  74.         send_len = string_toupper(read_buf, strlen(read_buf), write_buf);
  75.         write(connfd, write_buf, send_len);
  76.         if (strcmp("exit", read_buf) == 0)
  77.         {
  78.             printf("%s exit, child %d terminated\n", pthread->socket, tid);
  79.             close(connfd);
  80.             pthread->connfd = -1;
  81.             pthread_exit(NULL);
  82.         }
  83.     }
  84. }
  85. int main(void)
  86. {
  87.     int listenfd, connfd;
  88.     struct sockaddr_in server_sockaddr;
  89.     struct sockaddr_in client_addr;
  90.     char buf[1024];
  91.     char client_socket[128];
  92.     socklen_t length;
  93.     int idx;
  94.     int opt = 1;
  95.     server_sockaddr.sin_family = AF_INET;
  96.     server_sockaddr.sin_port = htons(PORT);
  97.     server_sockaddr.sin_addr.s_addr = inet_addr(IP);
  98.     listenfd = socket(AF_INET, SOCK_STREAM, 0);
  99.     if (listenfd < 0)
  100.     {
  101.         perror("socket error");
  102.         exit(1);
  103.     }
  104.     // 设置端口复用
  105.     setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  106.     if (bind(listenfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) < 0)
  107.     {
  108.         perror("bind error");
  109.         exit(1);
  110.     }
  111.     if (listen(listenfd, 5) < 0)
  112.     {
  113.         perror("listen error");
  114.         exit(1);
  115.     }
  116.     pthread_data_index_init();
  117.     while (1)
  118.     {
  119.         // 接受来自客户端的信息
  120.         printf("accept start \n");
  121.         memset(&client_addr, 0, sizeof(client_addr));
  122.         length = sizeof(client_addr);
  123.         if ((connfd = accept(listenfd, (struct sockaddr *)&client_addr, &length)) < 0)
  124.         {
  125.             if (errno == EINTR)
  126.                 continue;
  127.             else
  128.             {
  129.                 perror("accept error");
  130.                 exit(1);
  131.             }
  132.         }
  133.         idx = pthread_data_index_find();
  134.         if (idx == PTHREAD_MAX_SIZE)
  135.         {
  136.             printf("client connected upper limit, refused connect\n");
  137.             close(connfd);
  138.             continue;
  139.         }
  140.         memset(&client_socket, 0, sizeof(client_socket));
  141.         printf("client addr:%s por:%d\n",
  142.                inet_ntop(AF_INET, &client_addr.sin_addr, buf, sizeof(buf)),
  143.                ntohs(client_addr.sin_port));
  144.         snprintf(client_socket, sizeof(client_socket), "client socket (%s:%d)",
  145.                  inet_ntop(AF_INET, &client_addr.sin_addr, buf, sizeof(buf)),
  146.                  ntohs(client_addr.sin_port));
  147.         g_pthread_data[idx].connfd = connfd;
  148.         g_pthread_data[idx].cliaddr = client_addr;
  149.         strcpy(g_pthread_data[idx].socket, client_socket);
  150.         pthread_create(&(g_pthread_data[idx].pthread_id), NULL, pthread_handle, &(g_pthread_data[idx]));
  151.         pthread_detach(g_pthread_data[idx].pthread_id);
  152.     }
  153.     close(listenfd);
  154.     return EXIT_SUCCESS;
  155. }
复制代码
2-2 编译运行



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4