你调用一个第三方接口,明明收到了响应,但 Java 代码一直阻塞直到超时。
你看代码、看日志、看配置,全都没问题。
你怀疑网络,但 ping 通了,端口也是开的。
你陷入了僵局。
这时候,你需要 tcpdump——抓包就是网络世界的“行车记录仪”,它能回放每一帧数据,告诉你真相。
大家好,我是Evan,一个靠 tcpdump 抓包抓到过对方网关“悄悄丢包”的 Java+AI 学生。
今天,我用一次真实的线上排障案例,带你从零上手 tcpdump,教你用 Wireshark 分析TCP 重传、零窗口、RST 连接等异常信号,并学会区分“应用层没响应”和“网络层没送到”。
读完这篇,你再遇到“请求已发、响应不回”,手里就多了一把真正的“照妖镜”。
📌 写在前面
在智荟Agent项目的上线前夕,我们发现调用某外部大模型 API 时,大约有 5% 的请求会超时。日志显示“连接超时”,但对方的监控面板显示他们已经返回了 200。我们查了自己代码的线程池、连接池、GC,全都没问题。最后我抱着试试看的心态,在服务器上执行了tcpdump -i eth0 host api.llm.com -w bug.pcap,把抓到的包下载到本地用 Wireshark 打开——那一刻,真相大白:对方的网关在我们发完请求后,直接回了一个 TCP RST(重置连接)包,但我们的 HTTP 客户端根本没读到响应体,直接抛了超时异常。
从那以后,tcpdump 成了我排网络疑难杂症的“首选武器。
一、tcpdump 基础:30 秒就能上手
1.1 最常用的命令模板
bash tcpdump -i any host 192.168.1.100 -w dump.pcap-i any:监听所有网卡host 192.168.1.100:只抓与这个 IP 通信的包-w dump.pcap:写入文件,方便用 Wireshark 分析
1.2 常用抓包选项
| 选项 | 含义 |
|---|---|
-i eth0 | 指定网卡 |
host 8.8.8.8 | 按 IP 过滤 |
port 8080 | 按端口过滤 |
src host X | 只抓源 IP 是 X 的包 |
dst host X | 只抓目标 IP 是 X 的包 |
-s 0 | 抓取完整数据包(不截断) |
-n | 不进行 DNS 解析(加快速度) |
-c 100 | 只抓 100 个包后自动停止 |
-w file.pcap | 写入文件 |
-r file.pcap | 读取已有抓包文件 |
二、Wireshark 读包:你要找的 4 种“信号”
把dump.pcap下载到本地,用 Wireshark 打开。
你要看的是这四种信号:
2.1 正常的三次握手
text SYN → SYN+ACK → ACK如果抓包里没有看到SYN+ACK,说明对方根本没收到请求——防火墙拦截了,或者 IP/端口错了。
2.2 数据流的确认(ACK)
你的请求发出后,对方应该回复
ACK表示“我收到了你的数据”。如果只看到你的请求包,没看到任何
ACK,说明数据包在途中被丢弃了。
2.3 标志位:重传(Retransmission)
Wireshark 会把重传包标记为红色(TCP Retransmission)。
如果看到大量重传,说明网络存在丢包或拥塞。
2.4 标志位:零窗口(Zero Window)
Wireshark 标记为“TCP Zero Window”。
表示对方的接收缓冲区满了,无法再接收数据——你的应用还在傻等响应,但对方已经“撑”住了。
2.5 标志位:RST 包(连接重置)
Wireshark 标记为“RST”。
这是最关键的“暗号”,表示对方强行关闭了连接。
常见原因:
对方应用进程崩溃或主动终止了连接
防火墙检测到异常流量,直接丢掉连接
对方认为你的请求不符合协议规范(比如 HTTP 格式错误)
对方配置了“长连接超时”,主动切断了空闲连接
三、真实案例:“请求已发,响应不回”的真相
3.1 场景重现
第三方 API:
https://api.partner.com/v1/payment我们用
RestTemplate发 POST 请求请求超时设置 10s,但几乎每次到 5s 就报
ReadTimeout对方监控显示:他们收到了请求,也返回了 200,耗时仅 200ms
3.2 抓包分析步骤
步骤 1:定位连接
步骤 2:复现问题
执行一次请求,等待超时后停掉抓包。
步骤 3:Wireshark 查看流
用tcp.stream eq 0筛选出整个 TCP 流。
步骤 4:发现真相
Wireshark 显示如下时序:
text 14:23:01.123 Client → Server: POST /v1/payment (HTTP) 14:23:01.125 Server → Client: ACK (确认收到请求) 14:23:01.400 Server → Client: [TCP RST] (重置连接,目标端口 50820)关键结论:
对方收到了请求(看到了 ACK)
对方没有发出 HTTP 响应(没有
HTTP/1.1 200报文)对方直接发了一个
RST包但对方的业务日志说“返回了 200”
真相:对方的七层负载均衡在收到请求后,判定请求头不符合他们的“安全校验”,直接在 TCP 层发了 RST,但应用层日志的“返回 200”是从负载均衡网关日志里来的,而不是后端业务服务器的真实日志。
四、tcpdump 的进阶技巧
4.1 抓取 HTTP 请求体(方便排查协议错误)
bash # 抓取 HTTP 请求包,打印出其中的内容 tcpdump -i eth0 -A -s 0 'tcp port 8080 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'4.2 按时间段分割抓包文件
bash tcpdump -i eth0 -G 60 -w %Y%m%d_%H%M%S.pcap每 60 秒生成一个新文件,适合长期监控。
4.3 结合tcpdump和nc做连通性测试
bash # 抓包 + 发一个简单请求 echo -e "GET /health HTTP/1.0\r\n\r\n" | nc -w 5 192.168.1.100 8080📝 总结
| 故障现象 | 可能原因 | tcpdump 信号 |
|---|---|---|
| 请求发出,对方无任何回包 | 网络不可达 / 防火墙拦截 | 只看到 SYN,没有 SYN+ACK |
| 请求发出,对方回了 ACK,但无响应体 | 对方应用层处理异常 | 只有 ACK,没有应用层数据 |
| 收到 RST 包 | 对方主动关闭连接 | 红色 RST 标记 |
| 收到响应体,但 Java 仍超时 | 响应体不完整 / 分片丢失 | TCP 重传 + 未收全包 |
| 响应很慢 | 对方接收窗口为 0 | Zero Window 标记 |
核心结论:
tcpdump 是网络排障的“真相还原器”,它能帮你跳过所有日志的“谎言”。
遇到“请求已发、响应不回”时,先用 tcpdump 确认网络层是否正常,再查应用层。
RST 包是最关键的排查信号——它告诉你“对方在应用层之外就拒绝了你的连接”。
🤔思考题:
你在生产环境排查一个偶发的“响应超时”问题。该服务每天处理 10 万请求,只有不到 0.1% 的超时。你怀疑是网络问题,但用户侧和服务器侧的监控都显示网络延迟正常。你决定在服务端抓包 24 小时,但 24 小时的 pcap 文件可能高达几百 GB,无法直接保存到磁盘。
问题:你会用什么方法,既能持续抓包,又能及时“捕获”到那 0.1% 的异常 TCP 行为,而不浪费大量磁盘空间?(提示:考虑tcpdump的环形缓冲区、-C/-G参数、BPF 过滤表达式,或结合ngrep)
欢迎在评论区留下你的方案 —— 下一篇我会聊聊“网卡软中断与 CPU 飙升:为什么服务器si占用高达 80%?”