TIME_WAIT状态存在的理由:
1)可靠地实现TCP全双工连接的终止
在进行关闭连接四路握手协议时,最后的ACK是由主动关闭端发出的,如果这个最终的ACK丢失,服务器将重发最终的FIN,因此客户端必须维护状态信息允许它重发最终的ACK。如果不维持这个状态信息,那么客户端将响应RST分节,服务器将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。因而,要实现TCP全双工连接的正常终止,必须处理终止序列四个分节中任何一个分节的丢失情况,主动关闭的客户端必须维持状态信息进入TIME_WAIT状态。
2)允许老的重复分节在网络中消逝
TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个原来的迷途分节就称为lost duplicate。在关闭一个TCP连接后,马上又重新建立起一个相同的IP地址和端口之间的TCP连接,后一个连接被称为前一个连接的化身(incarnation),那么有可能出现这种情况,前一个连接的迷途重复分组在前一个连接终止后出现,从而被误解成从属于新的化身。为了避免这个情况,TCP不允许处于TIME_WAIT状态的连接启动一个新的化身,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个TCP连接的时候,来自连接先前化身的重复分组已经在网络中消逝。
新的SCTP协议通过在消息头部添加验证标志避免了TIME_WAIT状态。
*TIME_WAIT*
当一个socket进程结束后,相应的socket仍会保持TIME_WAIT状态4分钟。这样的目的是为了保证那些因某些原因在网络上传送很慢的包在这个scoket完全关闭之前到达。
这样后来使用同样的socket的进程不会收到本应发给前一个使用该socket的进程的数据包。
相关参数:
tcp_keepalive_interval
tcp_ip_abort_interval
tcp_close_wait_interval *
*FIN_WAIT_2*
当server收到一个关闭TCP连接的请求时,它会发一个设置了FIN位的packet给client。client会回应一个设置了ACK位的packet。然后,client会发送一个设置了FIN位的packet给server,server回应一个ACK,这个连接应关闭了。server接收到client的ACK,然后开始等待client的FIN包的状态就是FIN_WAIT_2。
在FIN_WAIT_2状态,server不会往client发送数据和控制信息,它只是等待client的FIN包。
相关参数:
tcp_fin_wait_2_flush_interval 系统将会flush
out处于FIN_WAIT_2状态的TCP连接的间隔,理论上最小值为6750ms。
*CLOSE_WAIT*
TCP连接总处于CLOSE_WAIT状态是由于当TCP没有开始协议中的CLOSE阶段。
TCP连接中CLOSE_WAIT状态的发生是当server没有收到应用程序的CLOSE,但应用程序已经终止了。这可能是一个有问题的应用程序在关闭窗口并结束之后发出了FIN包。有时候是当Solaris系统缺少kernal,tcp,ip,libnsl
或 rpcbind等patch造成。
CLOSE_WAIT状态意味着连接的另一端已经关闭了(被动关闭处于CLOSE_WAIT状态),而本地端仍在等待应用程序关闭。一个不确定的TCP连接指示着存在应用一级的bug。
在收到一个从远端发来的FIN之后,收到应用程序发出的CLOSE之前,TCP连接将从ESTABLISHED状态变为CLOSE_WAIT状态,
after从CLOSE_WAIT->
LAST_ACK的转换是在应用程序发出CLOSE时发生的。在转换过程中,TCP会安排(schedule)发送一个FIN,这个FIN将在保留的数据之后发出,如果接收端已经关闭了窗口可能会被延迟。
另外附一个TCP连接与释放截图: