计算机网络:TCP 三次握手为什么不是两次?
TCP 用三次握手建立连接,本质是双方都要确认"我能发、你能收",两次做不到这一点。
1. 两次握手差在哪
两次:A --SYN--> B
B --SYN+ACK--> A (B 认为连接已建立)
问题:B 无法确认 A 收到了自己的 SYN+ACK。如果这个包丢了,A 会重发 SYN,而 B 已经认为连接建好、 开始等待数据——资源被白白占用(半开连接)。
三次则补齐了最后一块拼图:
A --SYN(seq=x)--> B
A <--SYN+ACK(seq=y,ack=x+1)-- B
A --ACK(ack=y+1)--> B ← B 收到它才真正建连
2. 防止历史连接
更隐蔽的原因是旧连接的 SYN 迟到:A 发了个早就放弃的 SYN,网络延迟很久后才到 B。 两次握手时 B 直接建连,然后一直等一个不会来的数据;三次握手时 A 会回 RST,B 就不建了。
3. 握手为什么能省一次:SYN 与 ACK 合并
第二步 SYN+ACK 把"确认对方"和"发起自己"合并成一个包,所以最少就是三次。
四次也能建连(SYN、ACK、SYN、ACK),只是多一次往返、多一个 RTT。
4. 常见追问
Q:SYN 队列与 accept 队列?
半连接队列(SYN queue)存收到 SYN、还没完成三次握手的连接;全连接队列(accept queue)存已完成握手、
等待应用 accept() 的连接。SYN flood 打的就是前者,所以有 tcp_syncookies。
Q:为什么挥手要四次? TCP 是全双工,两个方向要各自关闭。收到 FIN 只代表"对方没数据发了",本端可能还有数据要发, 所以 ACK 与 FIN 不能合并(除非本端也正好没数据,那就是三次挥手)。
小结
三次握手是最小的可靠建连次数:两次无法让发起方确认对端收到了自己的确认, 也无法抵御迟到的历史 SYN。记住"两个方向、各需一次确认"就够了。