一.基于TCP套接字
1. 服务器主机崩溃
首先在不同的主机上运行客户端和服务器端,先启动服务器,在启动客户端。当连接建立后,从网络上断开服务器主机,这样同样模拟了客户发送数据时,服务器主机不可达的情况。
当客户端输入数据,由客户端TCP当做一个数据分节发出,接下来客户端就阻塞于recv调用等待接收数据,当服务器主机崩溃,已有的网络连接上发不出任何东西,所以客户TCP使用重传机制继续重传该数据分节,试图从服务器接受一个ACK。源于Berkeley的重传数据分节的次数为12次,放弃前等待的时间约为9分钟,当客户TCP最后终于放弃重传时(设这段时间服务器没有重启,或者服务器主机没有崩溃而是网络不可答),会返回客户端进程一个错误,因为客户端阻塞于recv的调用,他返回一个错误,假设是由于服务器主机崩溃,对客户数据的分节根本没有相应,则错误为ETIMEDOUT,但是如果是某些中间路由器判定服务器主机不可达,而以一个目的不可达ICMP消息相应。
尽管最终客户还是会发现对方已中断或不可达,但是要等待9分钟,然而有时想检测出这种崩溃状态,这就需要设置recv调用来设置超时时间来实现。
而套接字选项SO_KEEPALVE,他可以在客户端不主动向服务器数据时也可检测出服务器主机是否崩溃。
2.服务器主机崩溃后重启
如果客户在服务器主机崩溃时不主动发送发送数据给服务器,客户是不会知道服务器已经崩溃,如果主机服务器崩溃后重启,它的TCP将丢失崩溃前的所有连接消息,所以服务器的TCP接受所有客户端的数据均相应RST。在客户端,当RST到达时,客户端正阻塞于recv导致ECONNRESET错误。
3.服务器主机关闭
当系统关闭,一般由init进程给所有进程发信号SIGTERM(可以捕获此信号),等待一般固定时间(5-20s),然后给还在运行的进程发送sigkill(此信号不可捕获),这就给所有进程一小段时间来清除和终止。如果不捕获,则直接由SIGKILL终止
当进程终止,所有打开的套接字都终止,讲给client发送一个FIN,客户响应ACK,但是当前客户正阻塞于fgets,等待从终端获取输入,获得数据后,客户端将数据发送给server,这时send会返回正确,因为send只是将数据发送给缓冲区,当server收到来自客户端的数据后,由于先前打开的套接字已经终止,所以服务器会以RST相应。client接收到RST不会直接传给应用层,客户进程在调用send后立即调用send,这时会收到服务器端先前发送的FIN,recv立刻返回0.(因为连接已经处于RST状态,则不再有数据发出,而是SIGPIPE一个信号给应用层)
二.基于UDP套接字
1.服务器进程未运行
当客户发送UDP数据报给一个未运行的服务器时,服务器主机会以“端口不可答”的ICMP消息相应,但是此ICMP错误并不会返回给客户端进程,所以客户端阻塞于recvfrom