TCP 三次握手与四次挥手:为什么握手是 3 次,挥手通常是 4 次?
面试速答(30 秒版 TL;DR)
- 三次握手的目标是 建立连接并确认双方收发能力正常,同时同步初始序列号。
- 四次挥手的目标是 让连接的两个方向分别有序关闭,因为 TCP 是全双工。
- 三次握手不能省成两次,否则服务端无法确认客户端是否具备接收能力,也无法可靠确认旧连接报文不会干扰新连接。
- 四次挥手通常是四次,因为服务端收到
FIN后往往只能先回ACK,等自己数据发完再发FIN。 TIME_WAIT是面试高频追问,核心是两点:保证最后一个 ACK 可重发,以及 让旧报文在网络中自然消失。
先抓本质:TCP 不是“发过去就算完”
TCP 是面向连接、可靠、字节流的协议。
既然要可靠,它在正式传数据之前就要先确认状态;结束时也不能直接掐断,而要确保双方都收尾完毕。
三次握手:建立连接
每一步到底在确认什么
第 1 次:客户端发 SYN
含义是:
- 我想建立连接
- 我的初始序列号是
x
这一步后,服务端至少知道:客户端具备发送能力。
第 2 次:服务端回 SYN + ACK
含义是:
- 我收到你的 SYN 了
- 我的初始序列号是
y - 我确认你下一个应发送的是
x + 1
这一步后,客户端知道:
- 服务端收到了自己的请求
- 服务端也具备发送能力
第 3 次:客户端回 ACK
含义是:
- 我收到了你的 SYN
- 我确认你下一个应发送的是
y + 1
这一步后,服务端才知道:客户端具备接收能力,且双方序列号同步完成。
为什么不是两次握手
最常见的标准答法有两层:
1. 服务端需要确认客户端能接收
两次握手结束后,客户端知道服务端没问题,但服务端并不知道客户端是否收到了自己的 SYN+ACK。
2. 防止旧连接请求误导服务端
如果网络里残留了一个历史 SYN,服务端收到后就直接建立连接,会白白分配资源;而三次握手要求客户端必须再回一个 ACK,能降低旧报文导致误建连的风险。
四次挥手:关闭连接
为什么通常是四次
因为关闭连接要分别处理两个方向:
- 客户端告诉服务端:我这边发完了。
- 服务端确认:我知道你发完了,但我可能还有数据没发完。
- 服务端自己也发完后,再告诉客户端:我也发完了。
- 客户端最后确认。
这就是典型的四次挥手。
为什么挥手有时看起来像三次
如果服务端在收到客户端 FIN 时,恰好没有剩余数据要发,那么它可以把:
- 对客户端
FIN的确认 - 自己的
FIN
合并到一个报文里发出去。
但“通常情况”面试仍回答四次更稳,因为协议语义上它是两个动作。
TIME_WAIT 为什么重要
最后一个 ACK 发完后,主动关闭方不会立刻消失,而会进入 TIME_WAIT。
作用 1:防止最后 ACK 丢失
如果服务端没收到最后 ACK,它会重发 FIN。
主动关闭方处于 TIME_WAIT 时还能重发 ACK。
作用 2:隔离旧连接残留报文
等待一段时间后,网络中的旧报文基本会自然失效,这样新连接不会被旧连接的延迟报文污染。
面试里一句话:
TIME_WAIT不是浪费,而是 TCP 为可靠关闭付出的必要代价。
常见状态名要会认
如果面试官继续追问,可以简要提几个关键状态:
- 握手阶段:
LISTEN、SYN_SENT、SYN_RCVD、ESTABLISHED - 挥手阶段:
FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT、LAST_ACK、TIME_WAIT
其中最常见追问:
- 大量
TIME_WAIT说明谁主动关闭得多 - 大量
CLOSE_WAIT往往说明应用层没及时调用 close,程序可能有资源释放问题
高频题标准答法
1. 为什么握手是三次,挥手是四次?
握手时服务端可以把“收到你的 SYN”和“我的 SYN 也发给你”合并成一个报文;
挥手时服务端收到 FIN 后,不一定立刻能关闭自己的发送方向,所以通常先 ACK,后 FIN。
2. 第三次握手丢了会怎样?
客户端通常认为连接已建立;服务端收不到第三次 ACK,会重传第二次 SYN+ACK。
如果多次重传仍失败,服务端最终放弃这次连接。
3. 什么是半连接队列?
服务端收到 SYN 并回了 SYN+ACK,但还没收到最后 ACK,这时连接还没完全建立,通常处于半连接状态。
SYN Flood 攻击的核心就是大量占用这类资源。
4. 什么是 SYN Flood,怎么防?
攻击者伪造大量 SYN 请求,占满服务端半连接资源。
常见手段包括:SYN Cookie、缩短超时、增大 backlog、接入防护设备等。
5. 为什么 TCP 要有序列号?
为了保证:
- 数据有序重组
- 丢包重传定位
- 避免旧报文干扰新连接
易错点 / 坑
- 只会背“为了确认收发能力”但说不出谁确认谁。
- 忽略序列号同步这一层关键目的。
- 把
TIME_WAIT说成“没用的等待”。 - 把
CLOSE_WAIT和TIME_WAIT混淆。
速记要点(可背诵)
- 三次握手:建连 + 同步序列号 + 确认双方可收可发。
- 四次挥手:全双工连接要分两边各自关闭。
TIME_WAIT两个目的:保最后 ACK、隔离旧报文。CLOSE_WAIT多,优先怀疑应用没及时关闭 socket。