并发服务器---多进程

时间:2022-01-11 17:56:18

下面用多进程方式实现一个TCP并发服务器,每当一个新的客户端连接时fork一个子进程去和它通信。(各种主流的web服务器都不是纯粹的多进程方式运行,比如apache在每个进程中都用多路复用方式,直到连接数多到超过select可监听的最大描述符数时也会利用新的进程去处理。)

服务器端(server.c)

[cpp] view plain copy
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<string.h>  
  4. #include<sys/types.h>  
  5. #include<sys/socket.h>  
  6. #include<netinet/in.h>  
  7. #include<arpa/inet.h>  
  8.   
  9.   
  10. #define MAX_LISTEN 5  
  11. #define PORT 1987  
  12. #define IP "127.0.0.1"  
  13.   
  14. void serve_proc(int conn_fd)  
  15. {  
  16.     int recv_num;  
  17.     int send_num;  
  18.     char recv_buf[100];  
  19.     char send_buf[100];   
  20.   
  21.     int pid = getpid();  
  22.   
  23.     printf("client %d started\n", pid);  
  24.   
  25.     while (1) {  
  26.         //receive  
  27.         recv_num = recv(conn_fd, recv_buf, sizeof(recv_buf), 0);  
  28.         if (recv_num < 0) {  
  29.             close(conn_fd);  
  30.             exit(1);  
  31.         }  
  32.         recv_buf[recv_num] = '\0';  
  33.         printf("child proc %d got : %s\n", pid, recv_buf);  
  34.   
  35.         if (strcmp(recv_buf,"quit") == 0) {  
  36.             printf("child proc %d quit\n", pid);  
  37.             break;  
  38.         }  
  39.   
  40.         //send  
  41.         sprintf(send_buf, "server proc got %d bytes\n", recv_num);  
  42.         send_num = send(conn_fd, send_buf, strlen(send_buf), 0);  
  43.         if (send_num < 0) {  
  44.             close(conn_fd);  
  45.             exit(1);  
  46.         }  
  47.         printf("child proc %d sent : %s\n", pid, send_buf);  
  48.     }  
  49.   
  50.     close(conn_fd);  
  51. }  
  52.   
  53. int main()  
  54. {  
  55.     pid_t pid;  
  56.   
  57.     int conn_fd;  
  58.     int sock_fd = socket(AF_INET,SOCK_STREAM,0);  
  59.     if (sock_fd < 0) {  
  60.         perror("create socket failed");  
  61.         exit(1);  
  62.     }  
  63.   
  64.     struct sockaddr_in addr_client;  
  65.     int client_size = sizeof(struct sockaddr_in);  
  66.   
  67.     struct sockaddr_in addr_serv;  
  68.     memset(&addr_serv, 0, sizeof(addr_serv));  
  69.     addr_serv.sin_family = AF_INET;  
  70.     addr_serv.sin_port = htons(PORT);  
  71.     addr_serv.sin_addr.s_addr = inet_addr(IP);  
  72.   
  73.     if (bind(sock_fd,(struct sockaddr *)&addr_serv,sizeof(struct sockaddr_in)) < 0) {  
  74.         perror("bind error");  
  75.         exit(1);  
  76.     }  
  77.   
  78.     if (listen(sock_fd,MAX_LISTEN) < 0) {  
  79.         perror("listen failed");  
  80.         exit(1);  
  81.     }  
  82.   
  83.     while (1) {  
  84.         conn_fd = accept(sock_fd, (struct sockaddr *)&addr_client, &client_size);  
  85.         if (conn_fd < 0) {  
  86.             perror("accept failed");  
  87.             exit(1);  
  88.         }  
  89.   
  90.         pid = fork();  
  91.           
  92.         if (pid == 0) { // child proc   
  93.             close(sock_fd);  
  94.             serve_proc(conn_fd);  
  95.         } else { // main proc  
  96.             close(conn_fd);  
  97.         }  
  98.     }  
  99.           
  100.     close(sock_fd);  
  101.     return 0;  
  102. }  

客户端(client.c)

[cpp] view plain copy
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<string.h>  
  4. #include<sys/types.h>  
  5. #include<sys/socket.h>  
  6. #include<netinet/in.h>  
  7. #include<arpa/inet.h>  
  8.   
  9. #define REMOTE_IP "127.0.0.1"  
  10. #define REMOTE_PORT 1987  
  11.   
  12. int main()  
  13. {  
  14.         int sock_fd = socket(AF_INET, SOCK_STREAM, 0);  
  15.         if (sock_fd < 0) {  
  16.                 perror("create socket failed");  
  17.                 exit(1);  
  18.         }  
  19.   
  20.         struct sockaddr_in addr_serv;  
  21.         memset(&addr_serv, 0 ,sizeof(addr_serv));  
  22.         addr_serv.sin_family = AF_INET;  
  23.         addr_serv.sin_port = htons(REMOTE_PORT);  
  24.         addr_serv.sin_addr.s_addr = inet_addr(REMOTE_IP);  
  25.   
  26.         if (connect(sock_fd, (struct sockaddr *)&addr_serv, sizeof(struct sockaddr)) < 0) {  
  27.                 perror("connect failed");  
  28.                 exit(1);  
  29.         }  
  30.   
  31.   
  32.         int send_num, recv_num;  
  33.         char send_buf[100],recv_buf[100];  
  34.   
  35.         while (1) {  
  36.                 printf("Input MSG: ");  
  37.                 scanf("%s",send_buf);  
  38.                 send_num = send(sock_fd, send_buf, strlen(send_buf), 0);  
  39.                 if (send_num < 0) {  
  40.                         perror("send error");  
  41.                         exit(1);  
  42.                 }  
  43.   
  44.                 recv_num = recv(sock_fd, recv_buf, sizeof(recv_buf), 0);  
  45.                 if (recv_num < 0) {  
  46.                         perror("recv error");  
  47.                         exit(1);  
  48.                 }  
  49.                 recv_buf[recv_num] = '\0';  
  50.                 printf("Got : %s\n", recv_buf);  
  51.         }  
  52.   
  53.         close(sock_fd);  
  54.         return 0;  
  55. }  
代码都很简单啦,就是基本的收发数据。不过需要注意的一点是fork子进程以后需要对子进程关闭监听套接口,对父进程关闭连接套接口