CLOSING 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN 报文后,按理来说是应该先收到(或同时收到)对方的 ACK 报文,再收到对方的 FIN 报文。但是 CLOSING 状态表示你发送 FIN 报文后,并没有收到对方的 ACK 报文,反而却也收到了对方的 FIN 报文。
什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方在同时关闭一个链接的话,那么就出现了同时发送 FIN 报文的情况,也即会出现 CLOSING 状态,表示双方都正在关闭连接。
FIN_WAIT_2 状态的客户端接收服务端主机发送的 FIN + ACK 消息,并发送 ACK 响应后,会变为 TIME_WAIT
状态。处于 CLOSE_WAIT 的客户端发送 FIN 会处于 LAST_ACK 状态。
这里不少图和博客虽然在图上画的是 FIN + ACK 报文后才会处于 LAST_ACK 状态,但是描述的时候,一般通常只对于 FIN 进行描述。也就是说 CLOSE_WAIT 发送 FIN 才会处于 LAST_ACK 状态。
所以这里 FIN_WAIT_1 -> TIME_WAIT 的状态也就是接收 FIN 和 ACK 并发送 ACK 之后,客户端处于的状态。
然后位于 CLOSINIG 状态的客户端这时候还有 ACK 接收的话,会继续处于 TIME_WAIT 状态,可以看到,TIME_WAIT 状态相当于是客户端在关闭前的最后一个状态,它是一种主动关闭的状态;而 LAST_ACK 是服务端在关闭前的最后一个状态,它是一种被动打开的状态。
上面有几个状态比较特殊,这里我们向西解释下。
TIME_WAIT 状态
通信双方建立 TCP 连接后,主动关闭连接的一方就会进入 TIME_WAIT 状态。TIME_WAIT 状态也称为 2MSL
的等待状态。在这个状态下,TCP 将会等待最大段生存期(Maximum Segment Lifetime, MSL) 时间的两倍。
这里需要解释下 MSL
MSL 是 TCP 段期望的最大生存时间,也就是在网络中存在的最长时间。这个时间是有限制的,因为我们知道 TCP 是依靠 IP 数据段来进行传输的,IP 数据报中有 TTL 和跳数的字段,这两个字段决定了 IP 的生存时间,一般情况下,TCP 的最大生存时间是 2 分钟,不过这个数值是可以修改的,根据不同操作系统可以修改此值。
基于此,我们来探讨 TIME_WAIT 的状态。
当 TCP 执行一个主动关闭并发送最终的 ACK 时,TIME_WAIT 应该以 2 * 最大生存时间存在,这样就能够让 TCP 重新发送最终的 ACK 以避免出现丢失的情况。重新发送最终的 ACK 并不是因为 TCP 重传了 ACK,而是因为通信另一方重传了 FIN,客户端经常回发送 FIN,因为它需要 ACK 的响应才能够关闭连接,如果生存时间超过了 2MSL 的话,客户端就会发送 RST,使服务端出错。