一文看懂TCP状态转换图,详细梳理每个状态转换

时间:2024-04-09 14:25:00

TCP连接的建立和终止可用状态转换图来说明,如下图,这些状态可以用netstat显示,它他是一个在调试客户服务器应用时很有用的工具。
一文看懂TCP状态转换图,详细梳理每个状态转换

一文真正了解TCP三次握手和四次挥手-wireshark抓包分析中详解讲到了TCP三次握手和四次挥手全过程,并且用wireshark抓包详细分析了发送包的数据。
TCP为一个连接定义了11种状态,并且TCP规则规定如何基于当前状态及在线状态下所接受的包成为一个状态转换到另一个状态。举例来说,当某个应用进程在CLOSED状态之下主动打开时,TCP将发送一个SYN,且新的状态是SYN_SENED,如果这个TCP接受到一个带ACK的SYN,它将发送一个ACK,新的状态是ESTABLISHED。
一文看懂TCP状态转换图,详细梳理每个状态转换
另外几个状态的解释:

  1. 状态4.SYN_SEND—>状态3.SYN_RCVD:当客户端在发送 SYN 的同时也收到服务器端的 SYN请求,即两个同时发起连接请求,那么客户端就会从 SYN_SENT 转换到 SYN_REVD 状态.
  2. 状态3.SYN_RCVD—>状态2.LISTEN:服务器发生错误返回一个RST包,客户端接收编程LISTEN
  3. 状态6.FIND_WAIT_1—>状态7.CLOSED:服务器和客户端同时调用close函数断开连接,不过这种状态比较少见。
  4. 状态7.CLOSED—>状态9.TIME_WAIT:发送给服务器的FIN后,接受服务器的ACK包。

从上图可以看到TCP三次握手和四次挥手时的状态转换。
下面是另外一个视角,建议两者对比来查看。
一文看懂TCP状态转换图,详细梳理每个状态转换
从上图可以看到,当客户端应用程序主动请求关闭时,调用close或shutdown关闭连接,这时应用程序发送FIN包,进入状态FIN_WAIT_1,等待服务器发送确认包ACK,接收到ACK包后,客户端进入状态FIN_WAIT_2,等待服务器调用close,并发送FIN包,当客户端收到FIN后,发送ACK,进入最终的TIME_WAIT状态。
注意:主动执行关闭的那一端进入TIME_WAIT状态,留着TIME_WAIT的持续时间是MSL(最长分节声明周期 Maximum Segment Liftttime)的两倍,也就是2MSL,MSL一般适合30秒到2分钟,所以TIME_WAIT的时间一般为1-4分钟。
问题:为何要存在TIME_WAIT的状态?不可以直接到CLOSE的状态吗?
答:理由如下:

  1. **实现终止TCP全双工连接的可靠性。**假设最终的ACK包丢失(也就是上述8-9状态的那个ACK包丢失),服务器将重发最终的FIN,因此客户必须维护状态信息,以允许他重发最终的ACK。如果不维护状态信息,它将响应RST包,服务器将把该分解解释成一个错误。如果TCP打算执行所有必要的工作,已彻底终止某个连接上两个方向的数据流,那么它必须能够处理连接终止序列四个分解中任何一个分节丢失的情况。主动关闭的那一端必须进入TIME_WAIT状态,因为他可能不得不重发最终的ACK。
  2. 允许老的重复分节在网络中消失。,假设一个客户端与服务器建立连接后断开,这时在客户端和服务器又建立起连接,并且是相同的ip和端口号。TCP必须防止来自某个连接的老重复分组在连接终止后再现,从而被误解成属于同一个年级的化身。要实现这种功能,TCP不能给予TIME_WAIT的状态的连接启动新的化身,既然TIME_WAIT状态持续的时间是2MSL,这就足够让某个方向上的分组最多存活MSL秒即被丢弃,另一个方向上的应答最多存活MSL秒也被丢弃,通过实现这个规则,我们就能保证当成功建立一个TCP连接时,来自该连接先前的化身的老重复分组。你在网络中消失了。