加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

UNIX网络编程:并发服务器(TCP)

发布时间:2016-09-26 16:11:37 所属栏目:Unix 来源:站长网
导读:副标题#e# 在迭代服务器中,服务器只能处理一个客户端的请求,如何同时服务多个客户端呢?在未讲到select/poll/epoll等高级IO之前,比较老土的办法是使用fork来实现。 网络服务器通常用fork来同时服务多个客户端,父进程专门负责监听端口,每次accept一个新

上述程序利用了一点,就是父子进程共享打开的文件描述符,因为在子进程已经用不到监听描述符,故将其关闭,而连接描述符对父进程也没价值,将其关闭。当某个客户端关闭,则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个连接

UNIX网络编程:并发服务器(TCP)

查看本栏目更多精彩内容:http://www.bianceng.cn/OS/unix/

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读