35-并发服务器(多进程)

待你进一步完善了前面的 echo 服务器后,也处理了对端发送而来的 RST 段而导致的错误。现在,我们遇到了一个新问题,即客户端在关闭退出后,服务器也关闭退出了。

1. 让服务器永远运行

解决的办法很简单,我们将 server 改进为下面这样:

void server_routine() {    // bind, listen     while(1) {      sockfd = accept(listenfd);      doServer(sockfd);      close(sockfd);    } }

不过,这样改进有一个缺点,即服务器同时只能为一个客户端服务。如果在执行一个耗时的 doServer 的时候,又有客户端连接进来,那么这个后来客户端将迟迟得不到服务器的响应。

我们将上面这种服务器称为迭代服务器,如果 doServer 执行的任务非常简单,比如只是发送一下时间给对方,这种设计足够满足需求。如果是其它的耗时任务,这种设计则会让用户体验非常差。有各种各样的方案可以让我们挑选,不过,先来让我们用多进程的方案来解决它。

2. 基于多进程的并发服务器

基于多进程的并发服务器非常简单,我们只要将任务交给子进程处理就行了,而父进程只专注于接受新的连接,它的伪代码如下:

void server_routine() {    // bind, listen     while(1) {      sockfd = accept(listenfd);       // 让子进程去处理 IO      pid = fork();      if (pid == 0) {        // child        close(listenfd);        doServer(sockfd);        close(sockfd);        exit(0);      }       // father;      close(sockfd);    }    close(listenfd) }

3. 程序代码

代码托管在 gitos 上,请使用下面的命令获取:

git clone https://git.oschina.net/ivan_allen/unp.git

如果你已经 clone 过这个代码了,请使用 git pull 更新一下。本文所使用的程序路径是:

unp/program/echo/concurrent_server

4. 程序运行

  • 服务器在 sun 主机上运行
$ ./echo -s -h sun
  • 分别在 moon 和 flower 主机上启动两个客户端:
$ ./echo -h sun


这里写图片描述
图1 两个客户端都可以连接上服务器

  • 接下来,我按下 CTRL + D 关掉了 flower 主机上的客户端,然后又重新启动了一个,发现可以正常连接。但是,服务端这边貌似出了点问题!见图2.


这里写图片描述
图2 服务器端情况

可以看到图 2 中,多了一个僵小鱼,清理它对你来说不是什么难事,如果你学完了《Linux 环境编程》的话。如果你对此知识点有遗忘,请阅读这里的三篇文章:《wait 大战僵尸》《wait大变身之waitpid》《标准信号及其不可靠性》。相信你一定能解决此问题。

提示一下,如果你使用信号机制解决了问题后,可能会遇到新的坑。

最后,不管你有没有解决上面的问题,下一篇笔记我都得写^_^.

5. 总结

  • 迭代服务器及其使用场景
  • 掌握基本的多进程并发服务器模型

练习 1:将多进程服务器改为多线程模型(thread per connection, TPC).
练习 2:尝试测一下你的多进程服务器的并发数,也就是同时能够连接多少客户端。
思考:在 fork 出子进程后,子进程执行了 close(listenfd),为什么要这样做?说说你的理解。

最后,欢迎入群讨论:610441700,加群记得注明来意,否则会被拒绝。