启动我们的客户/服务器程序对,然后kill掉服务器子进程。看看客户端发生了什么?
服务器端查看结果:
zhaoxj$ netstat -antdp
(并非所有进程都能被检测到,所有非本用户的进程信息将不会显示,如果想看到所有信息,则必须切换到 root 用户)激活Internet连接 (服务器和已建立连接的)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:9877 0.0.0.0:* LISTEN 15578/tcpserv03
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:9877 127.0.0.1:35377 ESTABLISHED 15613/tcpserv03
tcp 0 0 127.0.0.1:35377 127.0.0.1:9877 ESTABLISHED 15612/tcpcli01
客户端(再打开一个终端):
zhaoxj$ ./tcpcli01 127.0.0.1
hello
hello
服务器端:
zhaoxj$ kill -9 15613 在这里kill掉服务器的子进程
zhaoxj$ child 15613 terminated
客户端:
zhaoxj$ ./tcpcli01 127.0.0.1
hello
hello
another line kill掉子进程后 键入此行 回车
str_cli: server terminated prematurely
具体过程如下:
1.kill掉子进程后,子进程中所有打开的描述字全部关闭,并向客户端发送一个FIN。而客户端TCP则响应一个ACK。
2.SIGCHLD信号被发送给服务器端的父进程
3.当我们键入"another line"时,str_cli调用writen,客户端TCP接着把数据发送给服务器。
TCP允许这么做,因为客户TCP接收到FIN只是表示服务器进程已关闭了服务器端的连接,服务器端不再发送任何数据。FIN的接收并没有告知客户端TCP服务器进程已经终止。
4.当服务器端TCP接收到来自客户端的数据时,先前打开的那个套接口的进程已经终止,于是响应一个RST。
5.然而客户进程看不到这个RST,因为它在调用wrien后立即调用readline,并且由于接收到的FIN,所调用的readline立即返回0.
6.当客户终止端时,它所有打开的描述字全部关闭
本例子的问题在于:当FIN到达客户端套接口时,客户正阻塞在fgets调用上。客户端实际上在对应两个描述字----套接口和终端输入,客户端不能单纯阻塞在这两个描述字中某个特定的输入上,而是应该阻塞在其中任何一个描述字的上。这正是select和poll这两个函数的目的之一。