TCP状态转换图

TCP 状态转换

  这个图 N 多人都知道,它排除和定位网络或系统故障时大有帮助,但是怎样牢牢地将这张图刻在脑中呢?那么你就一定要对这张图的每一个状态,及转换的过程有深刻的认识,不能只停留在一知半解之中。下面对这张图的11种状态详细解析一下,以便加强记忆!不过在这之前,先回顾一下TCP建立连接的三次握手过程,以及 关闭连接的四次握手过程。
image.png

图例解释:

  • 粗实线:代表主动的发起请求的一端
  • 虚线:代表被动接收请求的一端
  • 细线:代表内核操作的一些场景
  • CLOSED:表示初始状态。
  • LISTEN:该状态表示服务器端的某个SOCKET处于监听状态,可以接受连接。
  • SYN_SENT:这个状态与 SYN_RCVD 遥相呼应,当客户端 SOCKET 执行 CONNECT 连接时,它首先发送 SYN 报文,随即进入到了 SYN_SENT 状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT 状态表示客户端已发送 SYN 报文。
  • SYN_RCVD: 该状态表示接收到 SYN 报文,在正常情况下,这个状态是服务器端的 SOCKET 在建立 TCP 连接时的三次握手会话过程中的一个中间状态,很短暂。此种状态时,当收到客户端的 ACK 报文后,会进入到ESTABLISHED 状态。
  • ESTABLISHED:表示连接已经建立,可进行数据交换。
  • FIN_WAIT_1: FIN_WAIT_1 和 FIN_WAIT_2 状态的真正含义都是表示等待对方的 FIN 报文。区别是:
    • FIN_WAIT_1 状态是当 socket 在 ESTABLISHED 状态时,想主动关闭连接,向对方发送了 FIN 报文,此时该 socket 进入到 FIN_WAIT_1 状态。
    • FIN_WAIT_2 状态是当对方回应 ACK 后,该 socket 进入到 FIN_WAIT_2 状态,正常情况下,对方应马上回应 ACK 报文,所以 FIN_WAIT_1 状态一般较难见到,而 FIN_WAIT_2 状态可用 netstat 看到。
      -FIN_WAIT_2主动关闭链接的一方,发出FIN收到ACK以后进入该状态 。称之为半连接或半关闭状态。该状态下的socket只能接收数据,不能发。
  • TIME_WAIT: 表示收到了对方的 FIN 报文,并发送出了 ACK 报文,等 2MSL 后即可回到 CLOSED 可用状态。如果 FIN_WAIT_1 状态下,收到对方同时带 FIN 标志和 ACK 标志的报文时,可以直接进入到TIME_WAIT 状态,而无须经过 FIN_WAIT_2 状态。
  • CLOSING: 这种状态较特殊,属于一种较罕见的状态。正常情况下,当你发送 FIN 报文后,按理来说是应该先收到(或同时收到)对方的 ACK 报文,再收到对方的 FIN 报文。但是 CLOSING 状态表示你发送 FIN 报文后,并没有收到对方的 ACK 报文,反而却也收到了对方的 FIN 报文。什么情况下会出现此种情况呢?如果双方几乎在同时 close 一个 SOCKET 的话,那么就出现了双方同时发送 FIN 报文的情况,也即会出现CLOSING 状态,表示双方都正在关闭 SOCKET 连接。
  • CLOSE_WAIT: 此种状态表示在等待关闭。当对方关闭一个 SOCKET 后发送 FIN 报文给自己,系统会回应一个 ACK 报文给对方,此时则进入到 CLOSE_WAIT 状态。接下来呢,察看是否还有数据发送给对方,如果没有可以 close 这个 SOCKET,发送 FIN 报文给对方,即关闭连接。所以在 CLOSE_WAIT 状态下,需要关闭连接。
  • LAST_ACK: 该状态是被动关闭一方在发送 FIN 报文后,最后等待对方的 ACK 报文。当收到 ACK 报文后,即可以进入到CLOSED可用状态。

          image.png

          image.png

          image.png

填坑

为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

          image.png

  这是因为服务端的 LISTEN 状态下的 SOCKET 当收到 SYN 报文的建连请求后,它可以把 ACK 和 SYN(ACK 起应答作用,而 SYN 起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的 FIN 报文通知时,它仅仅表示对方没有数据发送给你了,但是你还可以给对方发送数据,也有这么种可能,你还有一些数据在传给对方的途中,所以你不能立马关闭连接,也即你可能还需要把在传输途中的数据给对方之后,又或者,你还有一些数据需要传输给对方后,(再关闭连接)再发送 FIN 报文给对方来表示你同意现在可以关闭连接了,所以它这里的 ACK 报文和 FIN 报文多数情况下都是分开发送的。

为什么 TIME_WAIT 状态还需要等 2MS L后才能返回到 CLOSED 状态?

  这是因为虽然双方都同意关闭连接了,而且握手的 4 个报文也都协调和发送完毕,按理可以直接回到 CLOSED 状态(就好比从 SYN_SEND 状态到 ESTABLISH 状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的 ACK 报文会一定被对方收到,因此对方处于 LAST_ACK 状态下的 SOCKET 可能会因为超时未收到 ACK 报文,而重发 FIN 报文,所以这个 TIME_WAIT 状态的作用就是用来重发可能丢失的 ACK 报文。

端口复用