为什么需要 TIME_WAIT 状态?
主动发起断开连接的一方才会有 TIME_WAIT 状态。而被动断开连接的一方在收到最后一个 ACK 报文后就会直接进入 Closed 状态。
TIME_WAIT 状态存在有两个原因
1)等待可能延迟的 ACK 报文。如果第四次握手即最后一个 ACK 报文因为网络原因丢失,服务端会因为没有收到 ACK 而超时重传 FIN 报文,处于 TIME_WAIT 状态的客户端可以继续对 FIN 报文做回复,向服务端发送 ACK 报文
假设客户端【没有】TIME_WAIT 状态,而是在发完最后一次回 ACK 报文就直接进入 CLOSED 状态,如果该 ACK 报文丢失了,服务端则重传的 FIN 报文,而这时客户端已经进入到关闭状态了,在收到服务端重传的 FIN 报文后,就会回 RST 报文。
服务端收到这个 RST 并将其解释为一个错误(Connection reset by peer),这对于一个可靠的协议来说不是一个优雅的终止方式
TIME_WAIT 时间过短或没有
2)保证让迟来的 TCP 报文有足够的时间被识别和丢弃。连接结束了,网络中的延迟报文也应该被丢弃掉,以免影响立刻建立的新连接。
假设 TIME-WAIT 没有等待时间或时间过短,举个例子:
服务端在关闭连接之前发送的 SEQ = 301 报文,被网络延迟了。 接着,服务端以相同的四元组重新打开了新连接,前面被延迟的 SEQ = 301 这时抵达了客户端,而且该数据报文的序列号刚好在客户端接收窗口内,因此客户端会正常接收这个数据报文,但是这个数据报文是上一个连接残留下来的,这样就产生数据错乱等严重的问题。 为了防止历史连接中的数据,被后面相同四元组的连接错误的接收,因此 TCP 设计了 TIME_WAIT 状态,状态会持续 2MSL 时长,这个时间足以让两个方向上的数据包都被丢弃(序列号对不上就会被丢弃),使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。
为什么 TIME_WAIT 状态持续时间是 2MSL?
MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
TIME_WAIT 状态持续 2MSL 时间的目的是:让一个 TCP 连接的两端发出的报文都从网络中消失
举个例子,客户端发送给服务端的最后一个 ACK 有两种可能性:
正常发送:如果 ACK 报文能够正常发送,假设客户端发送了 ACK 报文后过了一段时间 t 之后服务端才收到该 ACK,则有 0 < t <= MSL。因为客户端并不知道它发送出去的 ACK 要多久对方才能收到,所以客户端至少要维持 MSL 时长的 TIME_WAIT 状态才能保证这个 ACK 报文从网络中消失
丢失:如果客户端发出来的 ACK 报文丢失了,也就是第四次挥手丢失,那么服务端会重传 FIN 报文,所以,处于 TIME_WAIT 状态的客户端,要在收到这个 FIN 报文后再发送 ACK 报文,这两个报文需要经过 2MSL 的时间才能在网络中消失
所以,为了确保一个 TCP 连接的两端发出的报文都从网络中消失,客户端需要等待 2MSL 的时间
|