为什么tcp不能两次握手
TCP **不能用“两次握手”**的根本原因是:两次握手无法确保双方“都知道”连接是可靠建立的,容易引发“旧连接请求”造成错误连接。
🔁 先看标准的 三次握手(3-Way Handshake)流程
客户端 服务器| SYN (seq=x) ||------------------->| // 客户端请求连接| || SYN+ACK (seq=y) ||<-------------------| // 服务器确认并响应| || ACK (ack=y+1) ||------------------->| // 客户端确认
含义:
-
第一次(客户端→服务器):请求建立连接,发送
SYN
。 -
第二次(服务器→客户端):回应请求,发送
SYN + ACK
。 -
第三次(客户端→服务器):确认收到服务器回应,发送
ACK
,连接正式建立。
❌ 两次握手的问题是什么?
🧨 关键问题:服务器无法判断客户端是否“收到”自己的回应
假设两次握手:
-
客户端发送
SYN
。 -
服务器收到
SYN
,发送SYN + ACK
,并进入ESTABLISHED
状态。
如果客户端此时宕机或网络阻塞,服务器认为连接已建立,实际上客户端并不知道连接是否成功。此时:
-
服务器已分配资源(如线程、缓冲区);
-
客户端根本没进入连接状态;
-
后续的数据传输失败或被误接收;
-
更严重的是:旧的连接请求重传可能被误认为是新的连接请求(重放攻击)。
📌 举个例子(重放攻击场景):
-
客户端 A 发送一个旧的
SYN
包滞留在网络中; -
客户端 A 已关闭,但旧包现在才到服务器;
-
服务器收到旧
SYN
,回SYN+ACK
,此时认为有连接建立; -
如果此时客户端 A 再发送一个新的连接
SYN
,可能发生混淆; -
若是 两次握手,服务器无法分辨这个连接是“旧的”还是“新的”。
所以需要 第三次握手 来确认客户端“确实收到了服务器的响应”,才正式建立连接。
✅ 三次握手解决的问题
问题 | 两次握手 | 三次握手 |
---|---|---|
确保双方都准备好通信 | ❌ 否 | ✅ 是 |
防止旧连接重复建立 | ❌ 否 | ✅ 是 |
减少资源浪费(无效连接) | ❌ 否 | ✅ 是 |
✅ 总结
TCP 不能采用“两次握手”是因为:服务器无法确认客户端是否“收到并响应了”连接确认,这会导致错误连接、资源浪费,甚至安全问题。
三次握手是为了:
📌 重点:只有当客户端“真正在线并确认响应”,连接才成立。
✅ 2. 三次握手同步双方的初始序列号(ISN)
🔁 三次握手时双方完成 ISN 的交换:
📌 重点:三次握手完成了“数据传输编号的起点”同步,确保通信有序、可靠。
✅ 3. 三次握手避免资源浪费(尤其在服务端)
🧱 现代 TCP 实现中也有SYN Cookie技术,用于在 ACK 前不分配连接内存,从源头上对抗资源浪费。
📌 重点:三次握手让服务端“等你回应再正式投入资源”。
🔚 总结
功能 | 三次握手如何实现 |
---|---|
✅ 阻止旧连接重放 | 第三次 ACK 确认确保连接新鲜有效 |
✅ 同步双方序列号 | 客户端和服务器各发送一个 ISN |
✅ 减少资源浪费 | 服务端不在未确认连接上分配大量资源 |
所以,三次握手不是多此一举,而是 TCP 协议实现可靠、同步、安全通信的最小且必要步骤。
-
确保可靠连接建立;
-
防止因网络延迟导致的“旧连接请求”被误接受;
-
双方都确认对方已准备好通信。
✅ 三次握手原因
-
✅ 1. 三次握手可以阻止重复历史连接的初始化(防止重放旧连接)
-
网络环境中,旧的 SYN 包可能在延迟、丢包、缓存之后再次被送达服务器。
-
如果是两次握手,服务器在收到 SYN 后立刻建立连接,即使是个“幽灵连接”也会成立。
-
三次握手通过等待客户端的确认(第三次 ACK),避免了只凭 SYN 就建立连接,有效拦截了旧连接的重复利用(重放攻击)。
-
每次 TCP 连接,客户端和服务器都要生成一个 初始序列号(ISN),用来标识和确认数据包的顺序。
-
如果没有三次握手,服务器不知道客户端的 ISN,客户端也不知道服务器的 ISN,后续数据通信就无法可靠确认。
-
第一次:客户端发送自己的 ISN;
-
第二次:服务器回复自己的 ISN,并确认客户端的 ISN;
-
第三次:客户端确认服务器的 ISN。
-
服务端收到一个 SYN 后,并不会立刻分配大量资源(如线程、连接对象),而是进入 半连接状态(SYN_RECV);
-
如果没有收到第三次 ACK,连接不会正式建立;
-
这样可以防止攻击者伪造大量 SYN 包来拖垮服务器资源(也就是所谓的 SYN Flood 攻击)。