1.
服务器进程终止
假定此时服务器与客户端都已启动,并已建立连接。
此时客户端阻塞与fgets调用,并键入一行数据等待下一行,此时杀死服务器子进程
客户端再次输入数据之后:
整个过程图解如下
客户端接收到FIN(即处于CLOSE_WAIT状态),说明服务器已经关闭了连接,但是服务器并没有告知客户端TCP服务器已经终止。于是客户端继续发送数据,服务器响应一个RST,可以抓包看到:
192.168.197.5
192.168.197.10 Src=41839,Dst=9877,.AP...,S=1333764517
192.168.197.10
192.168.197.5
Src=9877 Dst=41839,...R..,S=2138602188
此问题说明了:客户端不能单纯阻塞在套接字和标准输入某个特定的源的输入(比如阻塞与fgets,但是不阻塞与socket),而应该阻塞在其中任何一个源的输入上,于是引入了select和poll,这是后话。
2.
服务器主机崩溃
首先服务器启动进程,客户端打开连接,并输入一行数据,然后让主机崩溃(虚拟机里面在点poweroff)
可以看到整个过程大概为15分钟,这也太夸张了!!原因是客户端发送完数据之后,
一直阻塞与read(从服务器到客户端)调用,然后一直重传,直到最后超时,客户最终会发现服务器主机已崩溃或主机不可达。解决的方法就是自己写一个read函数然后设置超时,或者加一个SO_KEEPALIVE选项。
3.
服务器主机崩溃后重启
这个实验也挺有意思,首先建立好连接,和上面一样,先输入一行,然后再输一行,
这时把主机崩溃了,再重启它。
抓包的情况看看:
192.168.197.10
192.168.197.5
Src=9877,Dst=41848,...R..,S=3100751727
可以看到服务器此时并没有启动服务器进程,当它重启之后收到了一个请求的连接,
于是对于来自客户的数据分节响应一个RST,客户阻塞与read调用,收到了这个RST之后便返回ECONNRESET错误。
4.
服务器关机
这里指的是正常关机,因为Unix系统关机时,会发送SIGTERM和SIGKILL信号,
SIGTREM可能忽略,但是SIGKILL信号不能忽略,于是服务器将由SIGKILL终止,当服务器子进程终止时,第一种情况(服务器进程终止)再次重演。 |