主题
概念卡片:TCP 三次握手与四次挥手
一句话机制:TCP 靠三次握手建立连接(双方确认自己与对方的收、发都正常),靠四次挥手释放连接(因为 TCP 是「半关闭」,一方发 FIN 只表示自己不再发数据,对方可能还要发,所以 ACK 与 FIN 必须分开)。握手的本质是交换并确认双方的序列号起始值(seq)。
三次握手时序
| 次 | 方向 | 标志位 | 序列号/确认号 | 状态 |
|---|---|---|---|---|
| 1 | C → S | SYN=1 | seq=x | C 进 SYN_SENT |
| 2 | S → C | SYN=1, ACK=1 | seq=y, ack=x+1 | S 进 SYN_RCVD |
| 3 | C → S | ACK=1 | seq=x+1, ack=y+1 | 双方进 ESTABLISHED |
每一轮「谁确认了什么」:
- 第一次:Client 什么都不能确认;Server 确认「对方发送正常、自己接收正常」。
- 第二次:Client 确认「自己收发正常、对方收发正常」;Server 仍只确认「对方发送正常、自己接收正常」。
- 第三次:双方都确认「自己收发正常、对方收发正常」。缺一不可。
为什么要三次,两次不行吗?
TCP 可靠传输的关键是维护序列号。三次握手 = 双方互相告知序列号起始值 + 确认对方已收到。若只有两次握手,至多只有客户端的起始序列号能被确认,服务器的序列号得不到确认,无法双向可靠。
四次挥手时序
| 次 | 方向 | 标志位 | 说明 |
|---|---|---|---|
| 1 | C → S | FIN=1 | C 关闭到 S 的数据传送,进 FIN-WAIT-1 |
| 2 | S → C | ACK=1 | S 确认收到(ack=seq+1),进 CLOSE-WAIT;C 进 FIN-WAIT-2 |
| 3 | S → C | FIN=1 | S 发完最后数据后发 FIN,进 LAST-ACK |
| 4 | C → S | ACK=1 | C 确认,进 TIME-WAIT(2MSL 后才 CLOSED);S 收到后立即 CLOSED |
FIN 报文即使不携带数据也要消耗一个序号;服务端结束连接比客户端早(客户端要等 2*MSL)。
为什么挥手要四次,三次不行吗?
FIN 只表示「对方没数据发给你了」,未必你也没数据发给对方。所以收到 FIN 的一方先回 ACK(表示收到),等自己数据发完再发 FIN。握手时 ACK 和 SYN 能一起发(SYN 请求可立即应答),挥手时 ACK 和 FIN 大概率分开发——故四次。
关键代码/报文示例
三次握手标志位变化:
C --SYN(seq=x)--> S
C <--SYN+ACK(seq=y,ack=x+1)-- S
C --ACK(seq=x+1,ack=y+1)--> S不变量(必须成立的约束)
- 握手确认「收发都正常」;挥手 ACK 与 FIN 分开发。
- SYN、FIN 都占用一个序号。
- 客户端 TIME-WAIT 要等 2*MSL(最长报文段寿命)才 CLOSED,用于保证最后一个 ACK 能到达、让旧连接报文在网络中消失。
常见误解
- 以为「两次握手就够」→ 服务器序列号无法被确认,不能建立双向可靠传输。
- 以为「挥手三次就够」→ 忽略 TCP 半关闭,ACK 和 FIN 因可能还有数据要发而必须分开。
- 以为「TIME-WAIT 是服务端状态」→ 是主动关闭方(客户端)的状态。
关联
- 可靠传输:概念卡片:TCP可靠传输与拥塞控制
- 总览:计算机网络技术栈总览