UNIX网络编程:并发服务器(TCP)
上述程序利用了一点,就是父子进程共享打开的文件描述符,因为在子进程已经用不到监听描述符,故将其关闭,而连接描述符对父进程也没价值,将其关闭。当某个客户端关闭,则read 返回0,退出循环,子进程顺便exit,但如果没有设置对SIGCHLD信号的忽略,则因为父进程还没退出,故子进程会变成僵尸进程。 现在先运行server,再打开另外两个终端,运行client(直接用<<UNIX网络编程——TCP回射服务器/客户端程序>>中的客户端程序),可以看到server输出如下: huangcheng@ubuntu:~$ ./serv recv connect ip=127.0.0.1 port=42114 recv connect ip=127.0.0.1 port=42115 在另一个终端ps一下: huangcheng@ubuntu:~$ ps -aux | grep serv /usr/lib/system-service/system-service-d 1000 3813 0.0 0.0 1640 404 pts/1 S+ 11:27 0:00 ./serv 1000 3815 0.0 0.0 1640 168 pts/1 S+ 11:27 0:00 ./serv 1000 3817 0.0 0.0 1640 156 pts/1 S+ 11:27 0:00 ./serv 1000 3824 0.0 0.0 3572 904 pts/3 S+ 11:28 0:00 grep --color=auto serv 发现共有3个进程,其中一个是父进程处于监听中,另外两个是子进程处于对客户端服务中,现在ctrl+c 掉其中一个client,由上面的分析可知对应服务的子进程也会退出,而因为我们设置了父进程对SIGCHLD信号进行忽略,故不会产生僵尸进程,输出如下: huangcheng@ubuntu:~$ ps -aux | grep serv 1000 3813 0.0 0.0 1640 404 pts/1 S+ 11:27 0:00 ./serv 1000 3815 0.0 0.0 1640 168 pts/1 S+ 11:27 0:00 ./serv 1000 3831 0.0 0.0 3572 904 pts/3 S+ 11:29 0:00 grep --color=auto serv 如果把第22行代码注释掉,上述的情景输出为: 1000 3876 0.0 0.0 1640 408 pts/1 S+ 11:32 0:00 ./serv 1000 3878 0.0 0.0 1640 172 pts/1 S+ 11:32 0:00 ./serv 1000 3880 0.0 0.0 0 0 pts/1 Z+ 11:32 0:00 [serv] <defunct> 1000 3885 0.0 0.0 3572 900 pts/3 S+ 11:33 0:00 grep --color=auto serv 即子进程退出后变成了僵尸进程。 如果不想忽略SIGCHLD信号,则必须在信号处理函数中调用wait处理,但这里需要注意的是wait只能等待第一个退出的子进程,所以这里需要使用waitpid函数,如下所示: signal(SIGCHLD, handler); ..................... void handler(int sig) { pid_t pid; int stat; /* wait(NULL); //只能等待第一个退出的子进程 */ /* 即使因为几个连接同时断开,信号因不能排队而父进程只收到一个信号 * 直到已经waitpid到所有子进程,返回0,才退出循环 */ while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) printf("child %d terminatedn", pid); return; } 1. 必须编写SIGCHLD信号的信号处理函数,原因为:防止出现僵死进程 2. 当捕获信号时,必须处理被中断的系统调用,原因为: (1)我们键入EOF字符来终止客户。客户TCP发送一个FIN给服务器,服务器响应以一个ACK。 (2)收到客户的FIN导致服务器TCP递送一个EOF给子进程阻塞中的read,从而子进程终止。 (3)当SIGCHLD信号递交时,父进程阻塞于accept调用。handler函数(信号处理函数)执行,其wait调用取到子进程的PID和终止状态,随后是printf调用,最后返回。 (4)既然该信号是在父进程阻塞于慢系统调用(accept)时由父进程捕获的,内核就会使accept返回一个EINTR错误(被中断的系统调用)。父进程不处理该错误,于是终止。 3. SIGCHLD的信号处理函数必须正确编写,应使用waitpid函数,以免留下僵死进程,原因为: 客户建立于服务器5个连接 查看本栏目更多精彩内容:http://www.bianceng.cn/OS/unix/ (编辑:云计算网_泰州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |