[关闭]
@lishuhuakai 2016-11-03T15:22:36.000000Z 字数 1777 阅读 1551

一起来写web server 02 -- 多进程版本


UNP的第30章客户/服务器程序设计范式中提到了这种模型.

主要的思想

这种模型的思想非常简单,具体来说,就是,没当用户connect到来之后,立马fork一个子进程去处理连接,代码如下:

  1. int main(int argc, char *argv[])
  2. {
  3. int listenfd = Open_listenfd(8080); /* 8080号端口监听 */
  4. while (true) /* 无限循环 */
  5. {
  6. struct sockaddr_in clientaddr;
  7. socklen_t len = sizeof(clientaddr);
  8. int connfd = Accept(listenfd, (SA*)&clientaddr, &len);
  9. addsig(SIGCHLD, sig_chld); /* 添加信号处理函数 */
  10. int pid;
  11. if ((pid = Fork()) == 0) /* 子线程 */
  12. {
  13. printf("\nnew process:%d\n", getpid());
  14. close(listenfd);
  15. doit(connfd); /* 处理连接 */
  16. close(connfd); /* 关闭socket描述符 */
  17. printf("\nend of process:%d\n", getpid());
  18. exit(0);
  19. }
  20. close(connfd);
  21. }
  22. return 0;
  23. }

借用stevens老爷子的一张图,应该是这么干的:
首先客户端通过conncect函数请求和服务器的连接.

接下来服务器调用Accept函数接收了对方的连接,connfd指代这个连接.

然后父进程调用fork函数生成了一个子进程.生成的子进程里面的数据和父进程是一模一样的,它也包含了这个connfd,所以现在客户和两个进程连接.

父进程关闭这个连接,然后由子进程来处理连接,这样一个交互就完成了.

需要注意的地方

僵死进程

子进程运行完毕之后,如果父进程不调用wait或者waitpid函数来处理处理的话,这些已经运行完成的子进程便成为了僵死进程,僵死进程会占用系统的资源,小部分的僵死进程还好,不过像我们这种需要长时间运行的服务器程序,点滴的僵死进程积累起来,这个量是非常恐怖的.所以对于僵死进程,我们是不能够忍受的.你可能会奇怪,为什么子进程运行完了还要父进程来收尸,直接释放资源不就好了吗?其实操作系统这么安排必定有它的道理,只是我们暂时用不到罢了.

设置僵死状态的目的是维护子进程的信息,以便父进程在以后某个时候获取,这些信息包括子进程的进程ID,终止状态以及资源利用信息(cpu时间,内存使用量等等).如果一个进程终止,而该进程有子进程处于僵死状态,那么它的所有僵死进程的父进程ID将会重置为1(init进程).继承这些子进程的init进程将清理他们(也就是说,init进程将wait它们,从而去除它们的僵死进程).

值得我们注意的是,当一个子进程运行完毕之后,系统会给父进程发送一个SIGCHLD信号,只要我们处理这个信号,就能够及时地回收子进程占用的一些资源.

所以在代码的第10行处addsig(SIGCHLD, sig_chld);,我们添加了SIGCHLD的信号处理函数.
函数如下:

  1. void
  2. sig_chld(int signo) /* 处理僵死进程 */
  3. {
  4. pid_t pid;
  5. int stat;
  6. while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
  7. printf("child %d terminated\n", pid);
  8. return;
  9. }

waitpid函数的第一个参数-1表示等待第一个终止的子进程,&stat可以获取终止进程的一些信息,而WNOHANG表示不用阻塞,不管有没有子进程终止,立即返回,没有子进程终止的话,会返回一个小于0的数,否则的话返回的是一个大于0的数.为什么要用while循环呢?很简单,因为系统是有子进程终止的时候才通知我们,不会因为僵死的子进程还未处理而同通知我们,所以我们要一次性将已经挂掉的子进程全部处理掉才行.

总结

这次的代码也非常简单,但是性能比之前的要强上不少.当然,这个能够同时处理的连接数目取决于系统可以生成的进程的数目.这次的代码是多进程版本的,下次的代码,我们就要编程多线程版本的啦.

代码可以在这里查看:https://github.com/lishuhuakai/Spweb

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注