面试题:TCP 三次握手为什么不能是两次

标准答案是"防止历史重复连接初始化"。但这题真正的分量在于你能不能用序列号把整个过程讲清楚。 核心:确认双方的双向收发能力 三次握手交换的是 ISN(Initial Sequence Number,初始序列号): 客户端 服务端 |----

标准答案是”防止历史重复连接初始化”。但这题真正的分量在于你能不能用序列号把整个过程讲清楚。

核心:确认双方的双向收发能力

三次握手交换的是 ISN(Initial Sequence Number,初始序列号):

客户端                                    服务端
  |-------- SYN, seq=x -------------------->|   客户端:我能发
  |<------- SYN+ACK, seq=y, ack=x+1 --------|   服务端:我能收,我也能发
  |-------- ACK, seq=x+1, ack=y+1 --------->|   客户端:我能收

两次握手只能证明客户端能发、服务端能收,服务端无法确认客户端是否能收到自己的包。第三次 ACK 补上这一环,双向信道才都验证完毕。

更关键的:防止历史连接

考虑一个真实场景:客户端发了一个 SYN 后超时重连,旧的 SYN 包延迟到达服务端。

  • 两次握手:服务端收到旧 SYN 就直接建立连接、分配资源,然后开始等数据——客户端根本不想连,资源白占
  • 三次握手:服务端先回 SYN+ACK,客户端发现 ack 的不是自己当前这个连接,回 RST 拒绝,服务端随即释放

序列号机制让服务端能判断”这是不是一次已经失效的旧请求”。

那四次行不行

理论上可以,但没必要。第二次可以把 SYN 和 ACK 合并成一个包(SYN+ACK),省一次往返。三次是满足需求的最小次数。

常见追问

Q:第三次握手可以带数据吗?

可以。前两次不能,因为连接还没建立,携带数据有安全风险(伪造源 IP 的放大攻击)。第三次时客户端已知服务端可达,放数据是安全的。这也是TCP Fast Open 的优化思路。

Q:SYN 洪水攻击怎么防?

攻击者大量发 SYN 而不回最后一个 ACK,把服务端的半连接队列打满。防御手段:

  • SYN Cookies:不立即分配资源,把状态编码进 ISN,收到合法 ACK 再重建
  • 缩小 tcp_syn_retries、增大半连接队列
  • 前置代理/防火墙做连接代理

Q:ISN 为什么是随机的?

防止序列号预测攻击——如果能猜出 ISN,就可以伪造包插入会话。随机化让预测成本极高。

怎么答出彩

先讲双向收发能力的验证,再讲历史重复连接的场景,最后补一句”三次是满足需求的最小次数,SYN+ACK 合并省了一次往返”。能画出序列号交互的,基本就过了。