Linux网络编程-自己动手写进程池

并发服务器的实现中,可以通过动态的创建子进程(或子线程)来实现。这样有几个缺点:

1、动态创建进程(或线程)比较耗时间,将导致客户响应较慢

2、动态创建的子进程或子线程通常只用来为一个客户服务,这导致系统中产生了很多进程或线程,使进程或线程之间的切换消耗很多CPU时间

3、动态创建子进程是当前进程的完整映像,当前进程需要谨慎管理其分配的文件描述符,否则子进程可能复制这些资源,导致系统可用资源急剧下降,进而影响服务器性能

        以上的几个缺点可以通过进程池来规避,进程池是由服务器预先创建一组子进程,一般数目在3-10之间,进程池中的所有子进程运行着相同的代码,应具有相同的属性,比如优先级、PGID等。当有新任务来时,主进程选择进程池中的一个子进程来为之服务,相比于动态创建子进程,选择一个已经存在子进程显然来得跟快。


        以下是我自己参考网络资料写的一个简单的进程池示例,进程间通信使用的是管道。

        该程序说明:主进程先创建两个管道,一个用于向子进程写数据,另一个用于子进程向主进程写数据。然后主进程再创建4个子进程,让4个子进程来进程处理客户的连接请求,然后给主进程发送信息,同时主进程也给子进程发送应答信息。

运行程序后的输出结果(比如端口设为60000):


在浏览器中输入http://192.168.1.2:60000(192.168.1.2运行该程序的主机)后就可以看到



源代码

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <sys/types.h>  
  4. #include <sys/socket.h>  
  5. #include <sys/stat.h>  
  6. #include <netinet/in.h>  
  7. #include <string.h>  
  8. #include <strings.h>  
  9. #include <unistd.h>  
  10. #include <signal.h>  
  11. #include <fcntl.h>  
  12.   
  13. #define err_sys(msg) \  
  14.     do { perror(msg); exit(-1); } while(0)  
  15. #define err_exit(msg) \  
  16.     do { fprintf(stderr, msg); exit(-1); } while(0)  
  17. #define head200 "HTTP/1.1 200 OK \r\n"  
  18. #define head404 "HTTP/1.1 404 Not Found\r\n"  
  19. #define head503 "HTTP/1.1 503 Service unabailiable\r\n"  
  20. #define MAXCHILD 4  
  21. #define BUFFSIZE 1024  
  22.   
  23. typedef struct  
  24. {  
  25.     pid_t pid;  
  26.     char status;  
  27. }sReport;  
  28.   
  29. int len200, len404, len503;  
  30. int pipe_fd1[2], pipe_fd2[2];  
  31.   
  32. void process_child(int listenfd, char* filename)  
  33. {  
  34.     int connfd;  
  35.     int cnt, len;  
  36.     struct sockaddr_in cliaddr;  
  37.     socklen_t clilen = sizeof(cliaddr);  
  38.     sReport req;  
  39.     char comm = '\0';  
  40.     int running = 1;  
  41.     char head_buf[1024];  
  42.   
  43.     req.pid = getpid();  
  44.     while(running)  
  45.     {  
  46.         connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);  
  47.         if(connfd < 0)  
  48.             err_sys("accept");  
  49.         req.status = 'n';  
  50.   
  51.         /* send message to parent process that got a new accept */  
  52.         if(write(pipe_fd1[1], &req, sizeof(req)) < 0)  
  53.             err_sys("write");  
  54.   
  55.         int fd;  
  56.         struct stat file_stat;  
  57.         if((fd = open(filename, O_RDONLY)) < 0)  
  58.             err_sys("open");  
  59.         if(stat(filename, &file_stat) < 0)  
  60.             err_sys("stat");  
  61.   
  62.         bzero(head_buf, sizeof(head_buf));  
  63.         len = 0;  
  64.         cnt = snprintf(head_buf, BUFFSIZE - 1, head200);  
  65.         len += cnt;  
  66.         cnt = snprintf(head_buf + len, BUFFSIZE - 1 - len, "Coontent-Length: %lu\r\n", file_stat.st_size);  
  67.         len += cnt;  
  68.         cnt = snprintf(head_buf + len, BUFFSIZE - 1 - len, "\r\n");  
  69.   
  70.         char *file_buf;  
  71.         struct iovec iv[2];  
  72.   
  73.         if((file_buf = (char *)malloc(file_stat.st_size)) == NULL)  
  74.             err_sys("malloc");  
  75.         bzero(file_buf, file_stat.st_size);  
  76.         if(read(fd, file_buf, file_stat.st_size) < 0)  
  77.             err_sys("read");  
  78.         iv[0].iov_base = head_buf;  
  79.         iv[0].iov_len = strlen(head_buf);  
  80.         iv[1].iov_base = file_buf;  
  81.         iv[1].iov_len = strlen(file_buf);  
  82.         writev(connfd, iv, 2); /* send the file to client host */  
  83.         free(file_buf);  
  84.   
  85.         close(fd);  
  86.         close(connfd);  
  87.   
  88.         req.status = 'f';  
  89.         /* tell parent process that finish the request */  
  90.         if(write(pipe_fd1[1], &req, sizeof(req)) < 0)  
  91.             err_sys("write");  
  92.         /* wait for commond from parent process */  
  93.         if(read(pipe_fd2[0], &comm, 1) < 1)  
  94.             err_sys("read");  
  95.   
  96.         if('e' == comm)  
  97.         {  
  98.             printf("[%d] exit\n", req.pid);  
  99.             running = 0;  
  100.         }  
  101.         else if('c' == comm)  
  102.             printf("[%d] continue\n", req.pid);  
  103.         else  
  104.             printf("[%d]: comm: %c illeagle\n", req.pid, comm);  
  105.     }  
  106. }  
  107.   
  108. void handle_sigchld(int sig)  
  109. {  
  110.     printf("the child process exit.\n");  
  111. }  
  112.   
  113. int main(int argc, char *argv[])  
  114. {  
  115.     int listenfd;  
  116.     struct sockaddr_in servaddr;  
  117.     pid_t pid;  
  118.   
  119.     if(argc != 2)  
  120.         err_exit("Usage: http-server port\n");  
  121.   
  122.     int port = atoi(argv[1]);  
  123.     len200 = strlen(head200);  
  124.     len404 = strlen(head404);  
  125.     len503 = strlen(head503);  
  126.   
  127.     if(signal(SIGCHLD, handle_sigchld) < 0)  
  128.         err_sys("signal");  
  129.     if(pipe(pipe_fd1) < 0)  
  130.         err_sys("pipe pipe_fd1");  
  131.     if(pipe(pipe_fd2) < 0)  
  132.         err_sys("pipe piep_fd2");  
  133.   
  134.     bzero(&servaddr, sizeof(servaddr));  
  135.     servaddr.sin_family = AF_INET;  
  136.     servaddr.sin_port = htons(port);  
  137.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  138.   
  139.     if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)  
  140.         err_sys("socket");  
  141.     if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)  
  142.         err_sys("bind");  
  143.     if(listen(listenfd, 10) < 0)  
  144.         err_sys("listen");  
  145.     int i;  
  146.     for(i = 0; i < MAXCHILD; i++)  
  147.     {  
  148.         if((pid = fork()) < 0)  
  149.             err_sys("fork");  
  150.         else if(0 == pid)  
  151.         {  
  152.             process_child(listenfd, "test.txt"); //test.txt为测试文件,内容为 Hello World!!!  
  153.         }  
  154.         else  
  155.         {  
  156.             printf("have create child %d\n", pid);  
  157.         }  
  158.     }  
  159.   
  160.     close(pipe_fd1[1]);  
  161.     close(pipe_fd2[0]);  
  162.     close(listenfd);  
  163.     char c = 'c';  
  164.     int req_num = 0;  
  165.     sReport req;  
  166.   
  167.     while(1)  
  168.     {  
  169.         if(read(pipe_fd1[0], &req, sizeof(req)) < 0)  
  170.             err_sys("read pipe_fd1");  
  171.         /* a new request come */  
  172.         if(req.status == 'n'//子进程收到一个连接请求  
  173.         {  
  174.             req_num++;  
  175.             printf("parent: %d have receive new request\n", req.pid);  
  176.         }  
  177.         else if(req.status == 'f'/* just finish a accept */  
  178.         {  
  179.             req_num--;  
  180.             if(write(pipe_fd2[1], &c, sizeof(c)) < sizeof(c))  
  181.                 err_sys("write");  
  182.         }  
  183.     }  
  184.     printf("Done\n");  
  185.   
  186.     return 0;  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值