有限状态机 多图详解TCP三次握手和四次挥手( 三 )

TCP 状态机

有限状态机 多图详解TCP三次握手和四次挥手

文章插图
 
 
上图是 TCP 的状态机 。
  1. CLOSED:状态时初始状态 。
  2. LISTEN:被动打开,服务器端的 状态变为 LISTEN (监听) 。被动打开的概念:连接的一端的应用程序通知操作系统,希望建立一个传入的连接 。这时候操作系统为连接的这一端建立一个连接 。与之对应的是主动连接:应用程序通过主动打开请求来告诉操作系统建立一个连接 。
  3. SYNRECVD:服务器端收到 SYN 后,状态为 SYN;发送 SYN ACK;
  4. SYN_SENTY:应用程序发送 SYN 后,状态为 SYN_SENT;
  5. ESTABLISHED:SYNRECVD 收到 ACK 后,状态为 ESTABLISHED; SYN_SENT 在收到 SYN ACK,发送 ACK,状态为 ESTABLISHED;
  6. CLOSE_WAIT:服务器端在收到 FIN 后,发送 ACK,状态为 CLOSE_WAIT;如果此时服务器端还有数据需要发送,那么就发送,直到数据发送完毕;此时,服务器端发送FIN,状态变为 LAST_ACK;
  7. FIN_WAIT_1:应用程序端发送 FIN,准备断开 TCP 连接;状态从 ESTABLISHED -> FIN_WAIT_1;
  8. FIN_WAIT_2:应用程序端只收到服务器端得 ACK 信号,并没有收到FIN信号;说明服务器端还有数据传输,那么此时为半连接;
  9. TIME_WAIT:有两种方式进入该状态:FIN_WAIT_1进入:此时应用程序端口收到 FIN+ACK(而不是像 FIN_WAIT_2 那样只收到 ACK,说明数据已经发送完毕)并向服务器端口发送 ACK;FIN_WAIT_2进入:此时应用程序端口收到了 FIN,然后向服务器端发送 ACK;TIME_WAIT 是为了实现 TCP 全双工连接的可靠性关闭,用来重发可能丢失的 ACK 报文;需要持续 2 个 MSL (最大报文生存时间):假设应用程序端口在进入 TIME_WAIT后,2 个 MSL 时间内并没有收到FIN,说明应用程序最后发出的 ACK 已经收到了;否则,会在 2 个 MSL 内在此收到ACK报文;
客户端应用程序的状态迁移图客户端的状态可以用如下的流程来表示:
CLOSED -> SYN_SENT -> ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> CLOSED以上流程是在程序正常的情况下应该有的流程,从书中的图中可以看到,在建立连接时,当客户端收到 SYN 报文的 ACK 以后,客户端就打开了数据交互地连接 。而结束连接则通常是客户端主动结束的,客户端结束应用程序以后,需要经历 FIN_WAIT_1,FIN_WAIT_2 等状态,这些状态的迁移就是前面提到的结束连接的四次握手 。
服务器的状态迁移图服务器的状态可以用如下的流程来表示:
CLOSED -> LISTEN -> SYN 收到 -> ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED在建立连接的时候,服务器端是在第三次握手之后才进入数据交互状态,而关闭连接则是在关闭连接的第二次握手以后(注意不是第四次) 。而关闭以后还要等待客户端给出最后的ACK 包才能进入初始的状态 。
其他状态迁移书中的图还有一些其他的状态迁移,这些状态迁移针对服务器和客户端两方面的总结如下
  • LISTEN -> SYN_SENT,对于这个解释就很简单了,服务器有时候也要打开连接的嘛 。
  • SYN_SENT -> SYN 收到,服务器和客户端在 SYN_SENT 状态下如果收到 SYN 数据报,则都需要发送 SYN 的 ACK 数据报并把自己的状态调整到 SYN 收到状态,准备进入ESTABLISHED
  • SYN_SENT -> CLOSED,在发送超时的情况下,会返回到 CLOSED 状态 。
  • SYN_收到 -> LISTEN,如果受到 RST 包,会返回到 LISTEN 状态 。
  • SYN_收到 -> FIN_WAIT_1,这个迁移是说,可以不用到 ESTABLISHED 状态,而可以直接跳转到 FIN_WAIT_1 状态并等待关闭 。
2 MSL 等待状态书中给的图里面,有一个 TIME_WAIT 等待状态,这个状态又叫做 2 MSL 状态,说的是在 TIME_WAIT2 发送了最后一个 ACK 数据报以后,要进入 TIME_WAIT 状态,这个状态是防止最后一次握手的数据报没有传送到对方那里而准备的(注意这不是四次握手,这是第四次握手的保险状态) 。这个状态在很大程度上保证了双方都可以正常结束,但是,问题也来了 。
由于插口的 2MSL 状态(插口是IP和端口对的意思,socket),使得应用程序在 2 MSL 时间内是无法再次使用同一个插口的,对于客户程序还好一些,但是对于服务程序,例如httpd,它总是要使用同一个端口来进行服务,而在 2 MSL 时间内,启动 httpd 就会出现错误(插口被使用) 。为了避免这个错误,服务器给出了一个平静时间的概念,这是说在 2 MSL 时间内,虽然可以重新启动服务器,但是这个服务器还是要平静的等待 2 MSL 时间的过去才能进行下一次连接 。


推荐阅读