TCP 连接管理:三次握手与四次挥手
TCP 是面向连接的可靠传输协议,连接建立与释放分别靠"三次握手"与"四次挥手"完成。这两张时序图是网络面试出现频率最高的考题,要求既能画图,又能解释"为什么是三次、为什么是四次"。
报文段关键字段
- 序号 seq:本报文段数据第一个字节的编号,用于排序与去重。
- 确认号 ack:期望收到的下一个序号,含义是"此前的字节我都收到了"。
- 标志位:SYN 建立连接、ACK 确认、FIN 关闭连接、RST 重置、PSH 立即交付。
三次握手:建立连接
目的是同步双方的初始序号,并确认双方收发能力都正常:
客户端 服务器
│ 1. SYN=1, seq=x │
│────────────────────────────────────>│ 服务器: SYN_RCVD
│ 2. SYN=1, ACK=1, seq=y, ack=x+1 │
│<────────────────────────────────────│
│ 3. ACK=1, seq=x+1, ack=y+1 │
│────────────────────────────────────>│ 服务器: ESTABLISHED
│ (客户端收到后进入 ESTABLISHED) │
为什么不能只握两次? 防止"已失效的连接请求"突然到达服务器:若第一次握手的请求因网络滞留后到达,服务器会误以为客户端要连接而白白建立空连接、浪费资源。第三次握手让服务器确认客户端确实想连,从而规避。
四次挥手:关闭连接
TCP 是全双工的,每一方向都要单独关闭,因此需要四次:
客户端 服务器
│ 1. FIN=1, seq=u (客户端不再发数据) │
│────────────────────────────────────>│
│ 2. ACK=1, ack=u+1 │
│<────────────────────────────────────│ 服务器继续发送剩余数据
│ 3. FIN=1, seq=w (服务器数据也发完) │
│<────────────────────────────────────│
│ 4. ACK=1, ack=w+1 │
│────────────────────────────────────>│ 服务器: CLOSED
│ 客户端等待 2MSL 后关闭 │
为什么挥手要四次? 被动关闭方收到 FIN 时可能还有数据要发送,不能把"确认"与"关闭"合并成一次,必须拆成 ACK 与 FIN 两步,故比握手多一次。
TIME_WAIT 的意义
主动关闭的一方在发出最后一个 ACK 后,要等待 2MSL(两倍最大报文段生存时间)才彻底关闭:
- 保证最后一个 ACK 若丢失,能有机会重发;
- 让本连接迟到的旧报文在网络中消亡,避免污染后续新连接。
运维中服务端出现大量 TIME_WAIT,常见于短连接频繁建立关闭的场景。
连接状态速查
| 状态 | 所处阶段 |
|---|---|
| LISTEN | 服务端在端口上等待连接 |
| SYN_SENT / SYN_RCVD | 三次握手进行中 |
| ESTABLISHED | 连接已建立,可传输数据 |
| FIN_WAIT_1 / FIN_WAIT_2 | 主动关闭方挥手中 |
| CLOSE_WAIT | 被动方等应用调用 close() |
| TIME_WAIT | 主动方等待 2MSL 后关闭 |
实战提示:netstat 看到大量 CLOSE_WAIT,通常说明对方关闭连接后,本端应用没有正确执行 close(),多半是代码漏关了连接或流未读完。
小结:三次握手同步序号并验证双向通道,四次挥手因全双工半关闭而多一拍。画熟两张时序图,讲清"为何三次/四次"与 TIME_WAIT 的作用,TCP 连接管理这道大题即可从容作答。