TCP 三次握手和四次挥手
TCP 连接建立和断开的过程及原理
问题
TCP 是如何建立和断开连接的?为什么需要三次握手和四次挥手?
解答
三次握手
TCP 是面向连接的协议,三次握手用于建立连接。
初始状态
客户端和服务端都处于 CLOSED 状态。客户端主动打开连接,服务端被动打开连接,结束 CLOSED 状态,开始监听,进入 LISTEN 状态。
第一次握手
客户端随机初始化序号 client_isn,将此序号置于 TCP 首部的序号字段中,同时把 SYN 标志位置为 1,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态。
第二次握手
服务端收到客户端的 SYN 报文后,随机初始化自己的序号 server_isn,将此序号填入 TCP 首部的序号字段中,把确认应答号字段填入 client_isn + 1,接着把 SYN 和 ACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态。
第三次握手
客户端收到服务端报文后,向服务端回应最后一个应答报文,该应答报文 TCP 首部 ACK 标志位置为 1,确认应答号字段填入 server_isn + 1,最后把报文发送给服务端。这次报文可以携带客户到服务器的数据,之后客户端处于 ESTABLISHED 状态。
服务端收到客户端的应答报文后,也进入 ESTABLISHED 状态,双方可以开始通信。
为什么需要三次握手?
两次握手不够的原因:
-
防止服务器开启无用连接:如果客户端发送的 SYN 报文因网络延迟到达服务器,服务器返回 SYN+ACK 后就建立连接。但如果这个返回报文丢失,客户端不知道连接已建立,会因超时重发请求。服务器会开启多个无用端口,造成资源浪费。
-
防止失效请求到达服务器:已失效的客户端请求因网络延迟到达服务器,如果没有第三次握手确认,服务器会误认为是有效请求而建立连接。
通过第三次握手,客户端告诉服务端是否收到了第二次握手的数据,以及连接序号是否有效。服务器根据这个信息决定是否正常建立连接。
四次挥手
TCP 断开连接需要四次挥手,双方都可以主动断开。以客户端主动关闭为例:
第一次挥手
客户端打算关闭连接,发送一个 TCP 首部 FIN 标志位被置为 1 的报文,即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。
第二次挥手
服务端收到该报文后,向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。
第三次挥手
客户端收到服务端的 ACK 应答报文后,进入 FIN_WAIT_2 状态。服务端处理完数据后,向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
第四次挥手
客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态。服务器收到 ACK 应答报文后,进入 CLOSED 状态,完成连接关闭。客户端在经过 2MSL 时间后,自动进入 CLOSED 状态,也完成连接关闭。
为什么需要四次挥手?
因为 TCP 是全双工通信,关闭连接时:
- 客户端发送 FIN 表示客户端不再发送数据,但还能接收数据
- 服务器收到 FIN 后先回 ACK,但可能还有数据需要处理和发送
- 服务器处理完数据后,再发送 FIN 表示同意关闭连接
服务端的 ACK 和 FIN 通常需要分开发送,所以比三次握手多了一次。
为什么 TIME_WAIT 要等待 2MSL?
MSL(Maximum Segment Lifetime)是 TCP 报文在传输过程中的最大生命周期。
客户端等待 2MSL 是为了确认服务器收到了最后的 ACK 报文:
- 如果服务器在 1MSL 内没收到 ACK,会重发 FIN 报文
- 客户端在 2MSL 内再次收到 FIN,说明服务器没收到 ACK,客户端重发 ACK 并重置计时器
- 如果 2MSL 内没再收到 FIN,说明服务器正常收到了 ACK,客户端可以安全关闭
这确保了连接的可靠关闭,也是客户端比服务端晚进入 CLOSED 状态的原因。
关键点
- 三次握手建立连接:SYN → SYN+ACK → ACK,第三次握手可以携带数据
- 三次握手的必要性:防止服务器开启无用连接,防止失效请求产生错误
- 四次挥手断开连接:FIN → ACK → FIN → ACK,因为 TCP 全双工需要双方分别关闭
- TIME_WAIT 等待 2MSL 是为了确保服务器收到最后的 ACK,保证连接可靠关闭
- 服务端的 ACK 和 FIN 分开发送,因为可能还有数据需要处理
目录