Linux c++ 进程池(转)

NO.1

一:什么是多进程模型

多进程模型是服务器在接收到大量高并发客户端访问时,通过创建多个子进程来与客户端进行通信。单进程阻塞在read()系统调用的时候,会导致服务器无法响应到其他的连接请求。这时可以通过fork()函数创建出多个子进程来处理业务,而主进程继续循环accept()其他客户连接,子进程实施具体的通信细节。

二:fork函数详解

NAME
       fork - create a child process       

 

SYNOPSIS
       #include <unistd.h> 
        pid_t fork(void);
DESCRIPTION
       fork()  creates  a  new  process by duplicating(复制) the calling process.  The new process, referred to as the child, is an exact(准确的)
       duplicate of the calling process, referred to as the parent, except for the following points:          

       *  The child has its own unique process ID, and this PID does not match the ID of any existing process group (setpgid(2)).

       *  The child's parent process ID is the same as the parent's process ID.

       *  The child does not inherit(继承) its parent's memory locks (mlock(2), mlockall(2)).

       *  Process resource utilizations(利用) (getrusage(2)) and CPU time counters (times(2)) are reset to zero in the child.

       *  The child's set of pending(挂起) signals is initially empty (sigpending(2)).

       *  The child does not inherit semaphore(信号量) adjustments from its parent (semop(2)).

       *  The child does not inherit record(记录) locks from its parent (fcntl(2)).

       *  The child does not inherit timers from its parent (setitimer(2), alarm(2), timer_create(2)).

 

       ......

RETURN VALUE
       On success, the PID of the child process is returned in the parent, and 0 is returned in  the  child.   On  failure,  -1  is
       returned in the parent, no child process is created, and errno is set appropriately(适当的).                       

ERRORS
       EAGAIN fork()  cannot  allocate  sufficient(足够的)  memory  to  copy the parent's page tables and allocate a task structure for the child.

       EAGAIN It was not possible to create a new process because the caller's RLIMIT_NPROC(用户可拥有的最大进程数) resource  limit  was  encountered(冲突).  

              To exceed this limit, the process must have either the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capability.

       ENOMEM fork() failed to allocate the necessary kernel structures because memory is tight(紧的).

       ENOSYS fork() is not supported on this platform(平台) (for example, hardware without a Memory-Management Unit).

所以由上可以总结出我们使用fork的“套路”:

 

[cpp]  view plain  copy
 
  1. pid_t pid;        
  2.   
  3. if  
  4. elseif  
  5.   
  6.   
  7.   
  8. else  
  9.   

 

 

 

三:服务器代码示例

下面是一个简单的回射服务器代码,服务器将客户端发送的代码回给客户端。

 

[cpp]  view plain  copy
 
  1. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/types.h> #define ERR_EXIT(sz) \ do while void connfd)  
  2.  recvbuf[1024];  
  3. for sizeof sizeof if break sizeof intvoid struct  listenfd;  
  4. if  
  5. sizeof   
  6.   
  7.   
  8.  on = 1;  
  9. ifsizeof  
  10. ifstructsizeof  
  11. if  
  12. struct  connfd;  
  13. sizeof  
  14. for ifstruct  
  15.   
  16.   
  17. if );  
  18. if  
  19.   
  20. else return }  

 

 

 

四:客户端代码示例

 

[cpp]  view plain  copy
 
  1. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/types.h> #define ERR_EXIT(sz) \ do while intvoid struct  sockfd;  
  2. if  
  3. sizeof );  
  4. ifstructsizeof  
  5.  sendbuf[1024] = {0};  
  6.  recvbuf[1024] = {0};  
  7. whilesizeof  
  8.   
  9. sizeof  
  10.   
  11. sizeof sizeof return }  

 

 

 

以上程序均经过测试。


NO.2

下面是一个进程池的实现:
[cpp]  view plain  copy
 
  1. #ifndef _PROCESS_POOL_H #define _PROCESS_POOL_H #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <stdlib.h> #include <sys/epoll.h> #include <signal.h> #include <sys/wait.h> #include <sys/stat.h> //描述一个子进程的类,pid_是目标子进程的pid,pipefd是父进程和子进程通信用的管道 class public    pipefd_[2];  
  2. //进程池类,将它定义为模板类是为了代码复用。其模板参数是处理逻辑任务的类 templatetypename class private  listenfd,  process_number = 8);   
  3. static public   
  4. static listenfd,  process_number = 8) {  
  5. static listenfd,  process_number = 8) {  
  6. if new return void private void void void private   
  7. staticconst MAX_PROCESS_NUMBER = 16;  
  8.   
  9. staticconst USER_PER_PROCESS = 65536;  
  10.   
  11. staticconst MAX_EVENT_NUMBER = 10000;  
  12.   
  13.  process_number_;  
  14.   
  15.  index_;  
  16.   
  17.  epollfd_;  
  18.   
  19.  listenfd_;  
  20.   
  21.  stop_;  
  22.   
  23. templatetypename //用于处理信号的管道,以统一事件源,后面称之为信号管道 static sig_pipefd[2];  
  24. static setnonblocking( fd)  
  25.  old_option = fcntl(fd, F_GETFL);  
  26.  new_option = old_option | O_NONBLOCK;  
  27. return staticvoid epollfd,  fd)  
  28. //从epollfd标识的epoll内核事件表中删除fd上的所有注册事件 staticvoid epollfd,  fd)  
  29. staticvoid sig)  
  30.  save_errno = errno;  
  31.  msg = sig;  
  32. *)&msg, 1, 0);  
  33. staticvoid sig, voidint restart = true struct sizeof if //进程池构造函数,参数listenfd是监听socket,它必须在创建进程池之前被创建, //否则子进程无法直接引用它,参数process_number指定进程池中子进程的数量 templatetypename  listenfd,  process_number)  
  34. false new   
  35. forint  ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sub_process_[i].pipefd_);  
  36. if continue else   
  37.   
  38. break  
  39.   
  40. //统一事件源,这个pipe不是用来和父进程通信的pipe templatetypename void  ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sig_pipefd);  
  41.   
  42.   
  43. //父进程中index_为-1,子进程中index_值大于等于0,我们据此判断接下来要运行的是父进程代码还是子进程代码 templatetypename void templatetypename void   
  44.  pipefd = sub_process_[index_].pipefd_[1];  
  45.   
  46.   
  47. new  number = 0;  
  48.  ret = -1;  
  49. while if break forint  sockfd = events[i].data.fd;  
  50. if  client = 0;  
  51.   
  52. *)&client, sizeof if continue else struct sizeof  connfd = accept(listenfd_, (struct if continue   
  53.   
  54. elseif  sig;  
  55.  signals[1024];  
  56. sizeof if continue else forint switch case  stat;  
  57. while continue break case case true break default break   
  58. elseif else continue delete templatetypename void   
  59.  sub_process_counter = 0;  
  60.  number = 0;  
  61.  ret = -1;  
  62. while if break forint  sockfd = events[i].data.fd;  
  63. if   
  64.  i= sub_process_counter;  
  65. do if  
  66. break while if  
  67. true break  new_conn = 1;    
  68. *)&new_conn, sizeof  
  69. elseif  sig;  
  70.  signals[1024];  
  71. sizeof if continue else forint switch case  stat;  
  72. while forint   
  73. if   
  74.   
  75. true forint if false break case case   
  76.   
  77. forint  pid = sub_process_[i].pid_;  
  78. if break default break else continue #endif  

服务器主程序:
[cpp]  view plain  copy
 
  1. #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <stdlib.h> #include <sys/epoll.h> #include <signal.h> #include <sys/wait.h> #include <sys/stat.h> #include "process_pool.h" class public sizeof public void epollfd,  sockfd, const void  idx = 0;  
  2.  ret = 1;  
  3.   
  4. whiletrue   
  5. if if break   
  6. elseif break else   
  7. for if) && (buf_[idx] == ))   
  8. break   
  9. if continue ;  
  10. * file_name = buf_;  
  11.   
  12. if   
  13. break   
  14. if break elseif   
  15. break  
  16. else   
  17. private   
  18. staticconst BUFFER_SIZE = 1024;  
  19. static  epollfd_;  
  20.          sockfd_;  
  21.         buf_[BUFFER_SIZE];  
  22.   
  23.          read_idx_;  
  24. int int argc, ** argv)  
  25. if return const* ip = argv[1];  
  26.  port = atoi(argv[2]);  
  27.  listenfd = socket(AF_INET, SOCK_STREAM, 0);  
  28.  ret = 0;  
  29. struct sizeof  on = 1;  
  30. sizeof structsizeof if return if delete return }  

CGI程序:
[cpp]  view plain  copy
 
  1. #include <stdio.h> int );  
  2. return }  

将CGI程序生成可执行文件,等候客户端请求。

客户端程序:
[python]  view plain  copy
 
  1. import )    
  2.     
  3. );  
  4. print data   

然后客户端就会输出,“hello,client”

posted on 2022-03-09 10:51  混元真人  阅读(257)  评论(0)    收藏  举报