【TCP】并发服务器<进程>

发布时间 2023-12-14 21:05:51作者: 素装写淡定
  1 #include <stdio.h>
  2 #include <strings.h>    //bzero
  3 #include <unistd.h>     //close
  4 #include <sys/socket.h> //socket
  5 #include <netinet/in.h> //struct sockaddr_in
  6 #include <arpa/inet.h>  //inet_addr
  7 #include <string.h>
  8 #include <signal.h>
  9 #include <sys/types.h>
 10 #include <sys/wait.h>
 11 #include <stdlib.h>
 12 
 13 void deal_son(int arg)
 14 {
 15     printf("即将回收子进程资源\n");
 16     wait(NULL);
 17     printf("已经回收子进程资源\n");
 18 }
 19 
 20 int main(int argc, char const *argv[])
 21 {
 22     // 1.创建套接字
 23     int sockfd = socket(AF_INET, SOCK_STREAM, 0);
 24     if (sockfd < 0)
 25     {
 26         perror("socket");
 27         return -1;
 28     }
 29     // 端口复用
 30     int yes = 1;
 31     setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
 32     // 2.绑定bind
 33     struct sockaddr_in my_addr;
 34     my_addr.sin_family = AF_INET;
 35     my_addr.sin_port = htons(8000);
 36     my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 机器的所有可用IP地址
 37     int ret = bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
 38     if (ret != 0)
 39     {
 40         perror("bind");
 41         return -1;
 42     }
 43     // 3.监听
 44     int backlog = 10;
 45     ret = listen(sockfd, backlog);
 46     if (ret < 0)
 47     {
 48         perror("listen");
 49         return -1;
 50     }
 51     // 4.提取,等待一个客户端连接
 52     struct sockaddr_in cli_addr;
 53     socklen_t len = sizeof(cli_addr);
 54     char buf[1024] = "";
 55     char ip[16] = "";
 56     int sockfd_new = 0;
 57     while (1)
 58     {
 59         // 保证提取到了正确的客户端,而不是被信号打断
 60         while (1)
 61         {
 62             sockfd_new = accept(sockfd, (struct sockaddr *)&cli_addr, &len);
 63             if (sockfd_new > 0)
 64                 break;
 65         }
 66 
 67         inet_ntop(AF_INET, (void *)&cli_addr.sin_addr, ip, 16);
 68         printf("提取到的客户端: %s--->%hu\n", ip, ntohs(cli_addr.sin_port)); // ip port
 69 
 70         pid_t pid = fork();
 71         if (pid < 0)
 72             close(sockfd_new);
 73         else if (pid == 0)
 74         {
 75             close(sockfd);
 76             // 5.循环收发消息
 77             while (1)
 78             {
 79                 bzero(buf, sizeof(buf));
 80                 recv(sockfd_new, buf, sizeof(buf), 0);
 81                 printf("接收到%s:%hu--->%s\n", ip, ntohs(cli_addr.sin_port), buf);
 82                 send(sockfd_new, "ok", sizeof("ok"), 0);
 83                 if (strcmp(buf, "quit") == 0)
 84                     break;
 85                 // 如果收到了0长度的数据包,意思客户端断开连接,子进程结束
 86                 if (strlen(buf) == 0)
 87                     break;
 88             }
 89             _exit(1);
 90         }
 91         else
 92         {
 93             close(sockfd_new);
 94             // 当子进程结束时,会给父进程发送SIGCHLD信号,父进程收到信号回收资源
 95             signal(SIGCHLD, deal_son); // 无阻塞
 96         }
 97     }
 98 
 99     // 6.关闭套接字
100     close(sockfd_new);
101     close(sockfd);
102     return 0;
103 }