Open LLLeon opened 5 years ago
TIME_WAIT 是主动关闭 TCP 连接一方在发出最后一个 ACK 后需要等待的状态,时长为 2MSL。TIME_WAIT 状态的存在主要有以下原因。(因为 TCP 连接的断开一般是由客户端发起关闭连接的操作,所以为了方便描述,后文把主动关闭方称为 C 端(Client),被动关闭方称为 S 端(Server)。)
因为 TCP 连接是全双工的,因此断开连接需要双方连接都关闭。整个断开连接的过程简要描述如下:
过程一:C 端发送 FIN,S 端收到后发送该 FIN 的 ACK; 过程二:S 端发送 FIN,C 端收到后发送该 FIN 的 ACK; 过程三:S 端收到 ACK。
要实现 TCP 全双工连接的正常终止,必须处理终止过程中四个报文中任何一个报文的丢失情况 。完成以上三个过程,才说明 TCP 全双工连接已经断开。
在过程三后,S 端就可以 100% 确认连接已经可以关闭,因此它便可以直接进入 CLOSED 状态了。然而对于 C 端来说,它无法确定最后发给 S 端的那个 ACK 是否已经被收到。根据 TCP 协议规范,不对 ACK 进行 ACK,因此它不可能再收到 S 端的 ACK 了。
那么在这里就陷入了僵局,TCP 连接的主动关闭方如何来保证整个断开连接过程的闭合?这时协议外的东西就起作用了。
TCP 报文段有一个超时值,即 MSL(Maximum Segment Lifetime),它是 TCP 报文段在网络上存在的最长时间,超过这个时间报文将被丢弃。MSL 在 RFC 1122 上建议是 2 分钟,而源自 berkeley 的 TCP 实现传统上使用 30 秒。TIME_WAIT 状态维持时间是 2MSL 时间长度,也就是在 1-4 分钟。
这类超时值非常重要,因为它们给出了一个物理意义上的不可逾越的界限,它们是自洽协议的唯一外部输入。
综上,如果这个 ACK 丢失,S 端将重发出最终的 FIN,因此 C 端必须要维持 TIME_WAIT 状态,以允许它重发最终的 ACK。如果 C 端不维持 TIME_WAIT 状态,而是在发出最终的 ACK 后就转为 CLOSED 状态,那么 C 端将响应 RST 报文,S 端收到后将此解释成一个错误(RST 表示复位,用来异常的关闭连接)。
等待 2MSL 时间主要目的是怕 S 端没收到最后一个 ACK,那么 S 端将在超时后重发第三次握手的 FIN 包,C 端接到重发的 FIN 包后可以再发一个 ACK 应答包。
分析 TIME_WAIT 时长是 2MSL 的原因:
TCP 报文可能由于路由器异常而“迷途”,在迷途期间,TCP 发送端可能因确认超时而重发这个报文,迷途的报文在路由器修复后也会被送到最终目的地,这个迟到的迷途报文到达时可能会引起问题。
在关闭前一个连接之后,马上又重新建立起一个相同的 IP 和端口之间的新连接,前一个连接的迷途重复分组在前一个连接终止后到达,而被新连接收到了。
为了避免这个情况,在 TIME_WAIT 状态下,上一次建立连接的套接字 (Socket) 将不可再重新启用,也就是同一个网卡 / IP 不可再建立同样端口号的连接,如果再重新创建系统将会报错。
要等待 TIME_WAIT 这个时间,也是为了避免有些报文段在网络上滞留,被对方收到的时候如果刚好又启用了一个完全一样的套接字,那么就会被认为是这个新连接的数据。因此为了让所有 “迷路” 的报文彻底消失后,才能启用相同的套接字。
TIME_WAIT 是主动关闭 TCP 连接一方在发出最后一个 ACK 后需要等待的状态,时长为 2MSL。TIME_WAIT 状态的存在主要有以下原因。(因为 TCP 连接的断开一般是由客户端发起关闭连接的操作,所以为了方便描述,后文把主动关闭方称为 C 端(Client),被动关闭方称为 S 端(Server)。)
1. C 端要确认 S 端是否有收到此 ACK
因为 TCP 连接是全双工的,因此断开连接需要双方连接都关闭。整个断开连接的过程简要描述如下:
要实现 TCP 全双工连接的正常终止,必须处理终止过程中四个报文中任何一个报文的丢失情况 。完成以上三个过程,才说明 TCP 全双工连接已经断开。
在过程三后,S 端就可以 100% 确认连接已经可以关闭,因此它便可以直接进入 CLOSED 状态了。然而对于 C 端来说,它无法确定最后发给 S 端的那个 ACK 是否已经被收到。根据 TCP 协议规范,不对 ACK 进行 ACK,因此它不可能再收到 S 端的 ACK 了。
那么在这里就陷入了僵局,TCP 连接的主动关闭方如何来保证整个断开连接过程的闭合?这时协议外的东西就起作用了。
这类超时值非常重要,因为它们给出了一个物理意义上的不可逾越的界限,它们是自洽协议的唯一外部输入。
综上,如果这个 ACK 丢失,S 端将重发出最终的 FIN,因此 C 端必须要维持 TIME_WAIT 状态,以允许它重发最终的 ACK。如果 C 端不维持 TIME_WAIT 状态,而是在发出最终的 ACK 后就转为 CLOSED 状态,那么 C 端将响应 RST 报文,S 端收到后将此解释成一个错误(RST 表示复位,用来异常的关闭连接)。
2. TIME_WAIT 的时间为什么是 2MSL
等待 2MSL 时间主要目的是怕 S 端没收到最后一个 ACK,那么 S 端将在超时后重发第三次握手的 FIN 包,C 端接到重发的 FIN 包后可以再发一个 ACK 应答包。
分析 TIME_WAIT 时长是 2MSL 的原因:
3. 处于 TIME_WAIT 状态的连接为什么不能启动一个新连接
TCP 报文可能由于路由器异常而“迷途”,在迷途期间,TCP 发送端可能因确认超时而重发这个报文,迷途的报文在路由器修复后也会被送到最终目的地,这个迟到的迷途报文到达时可能会引起问题。
在关闭前一个连接之后,马上又重新建立起一个相同的 IP 和端口之间的新连接,前一个连接的迷途重复分组在前一个连接终止后到达,而被新连接收到了。
为了避免这个情况,在 TIME_WAIT 状态下,上一次建立连接的套接字 (Socket) 将不可再重新启用,也就是同一个网卡 / IP 不可再建立同样端口号的连接,如果再重新创建系统将会报错。
要等待 TIME_WAIT 这个时间,也是为了避免有些报文段在网络上滞留,被对方收到的时候如果刚好又启用了一个完全一样的套接字,那么就会被认为是这个新连接的数据。因此为了让所有 “迷路” 的报文彻底消失后,才能启用相同的套接字。
4. 参考