news 2026/10/14 15:53:59

TCP 三次握手:为什么恰好是三次,不是两次或四次

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TCP 三次握手:为什么恰好是三次,不是两次或四次

抓包的时候看到那三行——SYN → SYN, ACK → ACK,很多人第一反应是“能通就行,为什么非得三次”。我刚学网络那会儿也这么想,直到有次线上服务出现大量CLOSE_WAIT连接堆积,才逼着自己把这个问题从头推了一遍。今天把“为什么是三次”讲透,顺便把面试会追问的延伸点一起收拾了。
先说结论:三次握手要解决的核心问题,不是“确认对面能收到”,而是双方都确认自己和对方的收发能力正常,并且对初始序列号达成一致。具体来说,这三次完成了四件事:客户端确认“我的发送 OK、你的接收 OK”;服务端确认“我的发送 OK、你的接收 OK”;双方交换初始序列号(ISN);双方确认这个连接是“新鲜”的,不是历史遗留的失效请求。第 4 条是最容易被忽略、也最能体现“为什么必须是三次”的一条。

一、为什么不能是两次

两次握手只能让服务端确认“客户端发的包我能收到”,但服务端无法确认“客户端能收到我发的包”。这还只是能力层面的问题,更严重的是历史失效连接请求。
看这个场景:客户端发了一个 SYN(seq=100),路上卡了很久。客户端超时后重发了新的 SYN(seq=200),这次连接建好、传完数据、正常关闭。这时候,那个卡住的老 SYN(seq=100)终于抵达服务端。
如果是两次握手,服务端收到老 SYN,会直接认为连接已建立,开始分配资源、等待客户端发数据。但客户端根本不知道这个连接存在——它早就关了。这份资源就一直空等,成了“半开连接”。攻击者拿这个做文章,就是 SYN 洪泛。
三次握手下,服务端收到老 SYN 后回 SYN-ACK,客户端一比对序列号(100 和自己期望的对不上),直接回 RST,服务端资源释放。一次往返解决。
TCP 的三次握手在 RFC 793 里定死,背后有 1983 年 Tomlinson 那篇讨论“在不可靠信道上建立可靠连接”的经典讨论:三次是最小可行次数,两次不足以判定连接的新鲜性。

二、为什么不是四次

看起来应该是四次:客户端 → SYN(我要连你);服务端 → ACK(我收到了);服务端 → SYN(我也要连你);客户端 → ACK(我收到了)。
但服务端要发的 ACK(确认你的 SYN)和 SYN(同步我的序列号),方向相同、时机相同,完全可以塞进同一个包里——这就是 SYN-ACK。所以:三次是理论最小值,四次是没必要的重复。
一句话记:握手要交换两个方向各一次“我准备好了”,而中间那次可以双向合并。

服务端客户端服务端客户端LISTEN 状态SYN_SENTSYN_RCVD双方 ESTABLISHED① SYN seq=x(我要连你,我的初始序号是 x)② SYN+ACK seq=y, ack=x+1(收到,我的初始序号是 y)③ ACK ack=y+1(收到你的 y,可携带数据)

三、序列号为什么必须同步

握手还有个隐藏任务:交换初始序列号。TCP 是字节流协议,每个字节都有序号。双方必须知道对方的起始序号,才能:判断哪些数据是新数据、哪些是重传;做流量控制和丢包检测;防止“旧连接的残包”被当成本次连接的数据。
如果 ISN 不在握手阶段对齐,后面所有序号都对不上,会话直接崩。而 ISN 的选取本身也不该是简单递增——现代实现会用时间戳 + 随机数生成,防止被猜测后注入数据。

四、几个实战延伸

半连接队列 vs 全连接队列。这两个队列经常被混着说,但排查问题时必须分清:半连接队列(syn queue)存储 SYN_RECV 状态的连接——收到 SYN、已回 SYN-ACK、还没收到 ACK;全连接队列(accept queue)存储三次握手已完成、等应用accept()取走的连接。线上“连接超时但服务进程活着”的典型原因,往往不是被攻击,而是全连接队列满了——应用accept()太慢,队列积压。

# 全连接队列溢出统计ss-lntnstat-azTcpExtListenOverflows TcpExtListenDrops

SYN 洪泛怎么防。核心武器是 syncookies:收到 SYN 时不分配连接资源,而是把连接状态信息编码进返回的 SYN-ACK 序列号里;客户端带着合法 ACK 回来时再解码校验,校验通过才真正建立连接。攻击者因为不回应 SYN-ACK,或回应的 ACK 无法通过哈希验证,其连接请求不占用任何资源。

# 开启 syncookiessysctl-wnet.ipv4.tcp_syncookies=1# 半连接队列上限sysctlnet.ipv4.tcp_max_syn_backlog# SYN-ACK 重试次数sysctlnet.ipv4.tcp_synack_retries

代价是丢失部分 TCP 选项(窗口扩大、SACK 等),大流量传输性能会受影响。现代 Linux 默认是“队列溢出时才启用”的混合策略。

五、四次挥手与 TIME_WAIT

握手建立连接,挥手断开。这里只讲两个最常被追问的点,完整的四次挥手流程见引用。
为什么挥手要四次?因为 TCP 是全双工——两端都可以同时发送和接收数据,两条“方向通道”是独立的。关闭连接时,必须双方都确认自己不再发送数据,才能彻底断开:客户端发 FIN(我不再发数据了);服务端回 ACK(收到了,但我可能还有数据要发);服务端发完数据后发 FIN(我也不发了);客户端回 ACK(好,彻底关闭)。中间的 ACK 和 FIN 不能合并,因为服务端收到 FIN 时可能还有数据没发完——这就是四次不能省成三次的原因。
为什么主动关闭方要等 2MSL?主动关闭方(如客户端)发完最后一个 ACK 后进入 TIME_WAIT 状态,持续 2 个报文最大生存时间(MSL),Linux 下 MSL 通常是 30 秒,即 60 秒。两个目的:确保最后的 ACK 能到达对端——如果服务端没收到 ACK,会重传 FIN,此时客户端还能重发 ACK;让旧连接的重复报文在网络中消逝——防止之前连接中延迟的、重复的数据包被新的、相同四元组(源IP、源端口、目的IP、目的端口)的连接错误地接收。

被动方(服务端)主动方(客户端)被动方(服务端)主动方(客户端)FIN_WAIT_1CLOSE_WAITFIN_WAIT_2LAST_ACKTIME_WAIT(等 2MSL)→ CLOSEDCLOSED① FIN(我不再发数据)② ACK(收到,但我可能还有数据)③ FIN(我也发完了)④ ACK(彻底关闭)

六、结语

回头看,“为什么是三次”这个问题的真正答案不是背出来的,而是推出来的:两次不足以判定连接的新鲜性,四次是没必要的重复——三次恰好是“过滤历史连接 + 双向确认能力 + 同步序列号”这三件事的理论最小完成次数。
再往上抽一层,这个结构在整个系列里反复出现——TCP 握手是“不可靠信道上建立可靠连接”问题的最小解,B+ 树是“磁盘 I/O 最小化”问题的最小解,三次握手和 B+ 树一样,都是“约束条件下恰好够用的工程最优解”。工程设计的精华从不在“多”,而在“恰好”——少一分不可,多一分浪费。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 15:53:59

智慧园林数字化治理:物联网+AI技术实践解析

1. 项目背景与行业痛点园林绿化行业正经历着从传统经验管理向数字化治理的转型阵痛期。我在参与多个城市园林项目时发现,养护工人凭经验浇水施肥、管理人员靠目测评估植物长势的现象仍然普遍存在。这种粗放式管理导致的问题包括:水资源浪费严重&#xff…

作者头像 李华
网站建设 2026/10/14 15:53:05

MMAction2 贡献指南:从 Fork 到 PR 的完整代码规范与提交流程

人工智能计算机视觉深度学习 【免费下载链接】mmaction2 OpenMMLabs Next Generation Video Understanding Toolbox and Benchmark 项目地址: https://gitcode.com/gh_mirrors/mm/mmaction2 点击查看 免费下载 导读 本文基于 docs/en/get_started/contribution_gu…

作者头像 李华
网站建设 2026/10/14 15:51:56

跨越“生产就绪”鸿沟:2026年企业级大模型API网关的底层逻辑重构

导语:从“功能可用”到“生产就绪”的阵痛与觉醒2026年,中国企业人工智能应用版图迎来了一次深刻的结构性跨越。如果说过去两年是百模大战的“技术炫技期”,那么今年则是大模型真正落地生根的“规模化生产期”。随着业务系统对大模型的调用量…

作者头像 李华
网站建设 2026/10/14 15:51:46

R语言平稳性检验实战:ADF、KPSS、PP组合判读与陷阱详解

做时间序列建模的人,几乎都遇到过一个让人头大的场景:同样的数据,ADF检验显示p值小于0.05,说明序列平稳;可换成KPSS检验,p值又小于0.05,反而说明序列不平稳。两个都是权威检验,结论却…

作者头像 李华