TCP 三次握手和四次挥手

TCP 连接建立和断开的过程及原理

问题

TCP 是如何建立连接和断开连接的?为什么需要三次握手和四次挥手?

解答

三次握手

TCP 通过三次握手建立连接,过程如下:

第一次握手

客户端从 CLOSED 状态发起连接。客户端随机生成初始序号 client_isn,将其放入 TCP 首部的序号字段,同时将 SYN 标志位置为 1,发送 SYN 报文给服务端。此时客户端进入 SYN-SENT 状态。

第二次握手

服务端收到 SYN 报文后,也随机生成自己的初始序号 server_isn,将其放入序号字段,同时将确认应答号字段设为 client_isn + 1,并将 SYN 和 ACK 标志位都置为 1,发送给客户端。此时服务端进入 SYN-RCVD 状态。

第三次握手

客户端收到服务端报文后,发送最后一个应答报文。将 ACK 标志位置为 1,确认应答号字段设为 server_isn + 1,发送给服务端。这个报文可以携带数据。之后客户端进入 ESTABLISHED 状态。

服务端收到第三次握手的报文后,也进入 ESTABLISHED 状态,连接建立完成。

为什么需要三次握手?

两次握手不够的原因:

  1. 防止无效连接浪费资源。如果客户端发送的 SYN 报文因网络延迟滞留,客户端超时后重发并完成连接。当旧的 SYN 报文最终到达服务端时,如果只有两次握手,服务端会误认为客户端要建立新连接,白白开启端口等待,造成资源浪费。

  2. 确认双方收发能力正常。三次握手可以让双方都确认对方能够正常接收和发送数据,确保连接的可靠性。

  3. 同步双方的初始序号。通过三次握手,双方都能确认对方的初始序号,为后续数据传输做准备。

四次挥手

TCP 通过四次挥手断开连接,任何一方都可以主动发起。以客户端主动关闭为例:

第一次挥手

客户端发送 FIN 报文(FIN 标志位置为 1),表示不再发送数据。客户端进入 FIN_WAIT_1 状态。

第二次挥手

服务端收到 FIN 报文后,发送 ACK 应答报文,进入 CLOSED_WAIT 状态。客户端收到 ACK 后进入 FIN_WAIT_2 状态。

第三次挥手

服务端处理完剩余数据后,发送 FIN 报文给客户端,表示也不再发送数据。服务端进入 LAST_ACK 状态。

第四次挥手

客户端收到服务端的 FIN 报文后,发送 ACK 应答报文,进入 TIME_WAIT 状态。服务端收到 ACK 后进入 CLOSED 状态。客户端等待 2MSL 后也进入 CLOSED 状态,连接完全关闭。

为什么需要四次挥手?

因为 TCP 是全双工通信,关闭连接时需要分别关闭两个方向的数据传输:

  1. 客户端发送 FIN 表示客户端不再发送数据,但仍可以接收数据。
  2. 服务端收到 FIN 后先回复 ACK,但此时服务端可能还有数据要发送。
  3. 等服务端数据发送完毕后,再发送 FIN 表示服务端也不再发送数据。
  4. 客户端收到后回复 ACK,完成连接关闭。

服务端的 ACK 和 FIN 需要分开发送,所以比三次握手多一次。

为什么 TIME_WAIT 要等待 2MSL?

MSL(Maximum Segment Lifetime)是 TCP 报文的最大生存时间。等待 2MSL 的原因:

  1. 确保服务端收到最后的 ACK。如果服务端没收到 ACK,会重发 FIN 报文。客户端在 1MSL 内可能收到重发的 FIN,再次发送 ACK 并重置计时器。

  2. 确保旧连接的报文在网络中消失。等待 2MSL 可以让本连接的所有报文都从网络中消失,避免旧连接的报文影响新连接。

如果 2MSL 内没有收到服务端的 FIN 重传,说明服务端已正常收到 ACK,客户端可以安全关闭连接。

关键点

  • 三次握手用于建立连接,确认双方收发能力正常并同步初始序号
  • 第三次握手可以携带数据,前两次不能携带数据
  • 四次挥手用于断开连接,因为 TCP 是全双工的,需要分别关闭两个方向
  • 服务端的 ACK 和 FIN 分开发送,导致需要四次挥手而不是三次
  • TIME_WAIT 等待 2MSL 是为了确保服务端收到最后的 ACK,以及让旧连接报文在网络中消失