UNIX网络编程:并发服务器(TCP)
先运行服务器程序,再运行客户端,客户端输出如下: huangcheng@ubuntu:~$ ./cli local ip=127.0.0.1 port=33867 local ip=127.0.0.1 port=33868 local ip=127.0.0.1 port=33869 local ip=127.0.0.1 port=33870 local ip=127.0.0.1 port=33871 huangcheng huangcheng 即每个连接的ip地址是一样的,但端口号不同,服务器方面通过accept返回的信息也打印出连接信息,如下: huangcheng@ubuntu:~$ ./serv recv connect ip=127.0.0.1 port=33867 recv connect ip=127.0.0.1 port=33868 recv connect ip=127.0.0.1 port=33869 recv connect ip=127.0.0.1 port=33870 recv connect ip=127.0.0.1 port=33871 huangcheng 当客户终止时,所有打开的描述符由内核自动关闭(我们不调用close,仅调用exit),且所有的5个连接基本在同一时刻终止。这就引发了5个FIN,每个连接一个,他们反过来使服务器的5个子进程基本在同一时刻终止。这又导致差不多在同一时刻有5个SIGCHLD信号递交给父进程: 我们预期所有的5个子进程都终止了。但是运行PS,我们发现其他4个子进程仍然作为僵死进程存在着。 正确的解决办法是调用waitpid而不是wait。我们必须指定WNOHANG选项,它告知waitpid在有尚未终止的子进程在运行时不要阻塞。我们不能再循环内调用wait,因为没有办法防止wait在运行的子进程尚未终止时阻塞。 注意前面的代码: while (1) { if ((conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen)) < 0) //3次握手完成的序列 { if( errno == EINTR ) ///////////////////////////////////////////////////////////////////必须处理被中断的系统调用 continue; else ERR_EXIT("accept error"); } 这段代码所做的事情就是自己重启被中断的系统调用。对于accept以及诸如read、write、select和open之类函数来说,这是合适的。不过有一个函数我们不能重启:connect。如果该函数返回EINTR,我们就不能再次调用它,否则将立即返回一个错误。当connect被一个捕获的信号中断而且不能重启时,我们必须调用select来等待连接完成。 (编辑:云计算网_泰州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |