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 状态,连接建立完成。
为什么需要三次握手?
两次握手不够的原因:
-
防止无效连接浪费资源。如果客户端发送的 SYN 报文因网络延迟滞留,客户端超时后重发并完成连接。当旧的 SYN 报文最终到达服务端时,如果只有两次握手,服务端会误认为客户端要建立新连接,白白开启端口等待,造成资源浪费。
-
确认双方收发能力正常。三次握手可以让双方都确认对方能够正常接收和发送数据,确保连接的可靠性。
-
同步双方的初始序号。通过三次握手,双方都能确认对方的初始序号,为后续数据传输做准备。
四次挥手
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 是全双工通信,关闭连接时需要分别关闭两个方向的数据传输:
- 客户端发送 FIN 表示客户端不再发送数据,但仍可以接收数据。
- 服务端收到 FIN 后先回复 ACK,但此时服务端可能还有数据要发送。
- 等服务端数据发送完毕后,再发送 FIN 表示服务端也不再发送数据。
- 客户端收到后回复 ACK,完成连接关闭。
服务端的 ACK 和 FIN 需要分开发送,所以比三次握手多一次。
为什么 TIME_WAIT 要等待 2MSL?
MSL(Maximum Segment Lifetime)是 TCP 报文的最大生存时间。等待 2MSL 的原因:
-
确保服务端收到最后的 ACK。如果服务端没收到 ACK,会重发 FIN 报文。客户端在 1MSL 内可能收到重发的 FIN,再次发送 ACK 并重置计时器。
-
确保旧连接的报文在网络中消失。等待 2MSL 可以让本连接的所有报文都从网络中消失,避免旧连接的报文影响新连接。
如果 2MSL 内没有收到服务端的 FIN 重传,说明服务端已正常收到 ACK,客户端可以安全关闭连接。
关键点
- 三次握手用于建立连接,确认双方收发能力正常并同步初始序号
- 第三次握手可以携带数据,前两次不能携带数据
- 四次挥手用于断开连接,因为 TCP 是全双工的,需要分别关闭两个方向
- 服务端的 ACK 和 FIN 分开发送,导致需要四次挥手而不是三次
- TIME_WAIT 等待 2MSL 是为了确保服务端收到最后的 ACK,以及让旧连接报文在网络中消失
目录