很多接口请求失败,真正的问题根本不在业务逻辑,而是在连接还没建立起来的时候就已经卡住了。只要 TCP 三次握手没有完成,后面的 HTTP、TLS、应用报文都不会开始。

TCP 排障最核心的一步,是把“连不上”继续拆开:到底是超时、拒绝、重置,还是中间链路有丢包和重传。现象一旦拆清,排查方向就会立刻收缩。

先把三次握手看成一个最小现场

三次握手本质上只有三步。

客户端发送 SYN,服务端回应 SYN, ACK,客户端再回一个 ACK,连接建立完成。

这个流程看起来简单,但只要中间任何一步缺失,表面现象就会完全不同。

  • 如果只有 SYN 发出,没有任何回应,常见表现是连接超时。
  • 如果收到 RST,常见表现是连接被重置或端口未监听。
  • 如果能握手成功,但后面很快异常断开,就要继续排查 TLS、应用协议或服务端处理。

所以排查 TCP 时,第一件事不是猜,而是先确认三次握手到底停在了哪一步。

最实用的几个命令

1
2
3
4
ss -tan
curl -v http://example.com:80
nc -vz example.com 80
sudo tcpdump -i any host example.com and port 80 -nn

ss -tan 用来看本机连接状态,curl -vnc 用来发起最小连接验证,tcpdump 用来保留真正的证据。

如果你要分析 HTTP 服务,curl -v 往往比浏览器更适合排障,因为它能把连接建立、请求发送和错误返回都明白打印出来。

一个典型的排查顺序

假设你访问某个服务失败,先做最小验证:

1
curl -v http://example.com:80

如果直接报 Connection refused,大概率是目标端口未监听,或者中间设备主动返回了拒绝。

如果长时间卡住后超时,更常见的是链路丢包、防火墙拦截或者目标不可达。

这时立刻抓包:

1
sudo tcpdump -i any host example.com and port 80 -w tcp-handshake.pcap

随后重新发起一次请求,再把包放进 Wireshark 看时序。

重点只看几个关键信号。

  • 有没有看到客户端发出的 SYN
  • 有没有收到服务端的 SYN, ACK
  • 有没有出现 RST
  • 是否存在重复 SYN 重传。

如果 SYN 一直重传却没有回应,说明请求大概率已经发出,但对端没有响应回来。

如果一开始就收到 RST,往往是端口未开、服务未监听,或者中间层主动拒绝。

如果三次握手成功,但连接建立后立刻断开,说明 TCP 层基本没问题,应继续往上看 TLS 或应用层。

用连接状态辅助判断

除了抓包,ss -tan 也很有帮助。

常见几个状态值得重点看。

  • SYN-SENT:本机已发起连接,正在等对端回应。
  • ESTAB:连接已经建立。
  • TIME-WAIT:连接刚关闭,正在等待迟到报文消失。
  • CLOSE-WAIT:对端已关闭,本端还没完全收尾。

如果你在故障时看到大量连接停在 SYN-SENT,那就很值得怀疑是目标不可达、丢包或者中间网络设备拦截。

常见误判

最常见的误判之一,是把“连不上”直接等同于“服务挂了”。实际上,DNS 错误、路由异常、防火墙策略、负载均衡丢包,都可能让连接建立失败。

第二个常见误判,是看到 curl 报错就去改代码。很多时候请求根本还没进入业务处理阶段,应用代码完全没机会执行。

第三个常见误判,是只看一条命令输出,不保留现场证据。TCP 排障里,时序特别重要,没有抓包就很难真正说清是哪里先出了问题。

一个值得自己做的小实验

你可以在本机选一个正常开放端口和一个未监听端口,对比它们的行为差异。

1
2
3
nc -vz 127.0.0.1 22
nc -vz 127.0.0.1 65000
sudo tcpdump -i lo tcp and '(port 22 or port 65000)' -w tcp-local-demo.pcap

然后重点观察。

  • 正常端口的三次握手如何完成。
  • 未监听端口是否立即返回 RST
  • ss -tan 在连接建立前后有哪些状态变化。

只要把这组实验走一遍,你以后看到“连接失败”这四个字时,就不会只剩下模糊的焦虑,而是会自然想到该先看哪几个信号。

小结

TCP 三次握手是网络排障里最值得练熟的第一个现场。因为它足够基础,也足够关键。只要你能把连接失败继续拆成超时、拒绝、重传和重置几类现象,再配合 ss 和抓包去验证,很多原本笼统的“网络不通”问题,就会迅速变成可定位的问题。