三次握手是TCP建立可靠连接的必要过程:客户端发SYN,服务器回SYN+ACK,客户端再发ACK;其核心在于确认双方收发能力正常、防止失效请求、避免资源浪费,并严格遵循RFC 793规范。

HTML 面试题里混进 TCP 三次握手,说明面试官在考察你是否真懂「浏览器发起一个 HTTP 请求前底层发生了什么」——不是背流程,而是要能串起 socket、connect()、状态机和网络异常处理。
connect() 调用后到底发生了什么
浏览器执行 fetch() 或新建 XMLHttpRequest 时,内核会调用系统 connect() 函数。这个调用本身不发包,只是把 socket 置为 SYN_SENT 状态并触发内核协议栈行为:
- 内核立即构造并发出第一个 SYN 报文(含随机
ISN),不等用户态代码返回 - 若目标端口无服务监听,通常在超时(约1秒)后返回
Connection refused错误,对应 RST 响应 - 若网络丢包或防火墙拦截 SYN,
connect()会阻塞直到超时(Linux 默认约75秒),最终报Operation timed out -
connect()返回成功 ≠ 连接已建立,只表示第三次 ACK 已被内核确认,socket 进入ESTABLISHED
为什么第二次握手必须是 SYN+ACK 而不能拆成两个包
服务器收到 SYN 后,必须在同一个报文中同时设置 SYN=1 和 ACK=1 标志位,原因很实际:
- 避免额外 RTT:如果拆成「SYN → ACK」两步,连接建立要 4 次往返,延迟翻倍
- 防止资源耗尽:仅发 SYN 不带 ACK,服务器需在内存中维护半开连接(
SYN_RCVD),等待后续 ACK;若攻击者伪造海量 SYN 却不发第三次,就会触发 SYN Flood - TCP 规范强制要求:RFC 793 明确规定第二次握手必须携带自己的
ISN并对客户端ISN+1 确认,单个报文才能满足这两个动作
抓包看到只有两次握手?可能是连接复用或 TLS 握手干扰
用 wireshark 抓浏览器流量时,常发现 HTTP/1.1 请求没有明显三次握手过程,这不是协议失效,而是:
- 连接池复用:浏览器对同一域名默认保持 6 个空闲
ESTABLISHED连接,后续请求直接复用,不触发新握手 - TLS 夹带:HTTPS 请求中,TCP 握手完成后立刻开始 TLS
ClientHello,但三次握手报文可能被过滤器折叠或时间轴压缩导致视觉上「看不见」 - 本地回环优化:
localhost或127.0.0.1场景下,Linux 内核可能绕过部分协议栈逻辑,SYN/ACK 在环回接口内快速完成,抓包位置不当就捕获不到 - 注意看 TCP flags 字段:
SYN、SYN-ACK、ACK的 flag 组合(如[S]、[S.]、[.])比报文顺序更重要
真正容易被忽略的是:三次握手期间任何一环节失败,应用层拿到的错误非常笼统(比如 net::ERR_CONNECTION_TIMED_OUT),但背后可能是 SYN 未达、SYN+ACK 被丢、或 ACK 回不来——定位得看服务端 ss -s 输出里的 SYNRECV 数量,而不是只盯着客户端日志。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











