应用日志里出现 "connection reset by peer",应用端代码看着没问题,
对端代码看着也没问题。这类问题 70% 是中间链路(LB / 防火墙 / 反代)
干的。抓包是唯一直接定位的办法。
1. 收集足够的现场信息
before 开抓之前,先列清楚四元组:
# 客户端
ss -tan state established '( dport = :8080 or sport = :8080 )'
# 服务端
ss -tan state established '( sport = :8080 )'
记下 src / dst IP + port。
2. tcpdump 命令
服务端:
sudo tcpdump -i any \
-s 0 \
-w /tmp/svr.pcap \
'tcp port 8080'
客户端(如果可以同时抓):
sudo tcpdump -i eth0 -s 0 -w /tmp/cli.pcap 'host <server-ip> and tcp port 8080'
-s 0不截断 payload(默认 96 字节,分析 HTTP / TLS 不够看)-i any在 Linux 上抓所有接口(不知道走哪个就用这个)- 写文件比直接终端打印好 100 倍 —— 终端文本格式会丢字段、丢顺序
跑出问题后 Ctrl-C 停。
3. 快速浏览
# 文本看一眼
tcpdump -r /tmp/svr.pcap -n -nn -c 20
# 只看 RST 包
tcpdump -r /tmp/svr.pcap -n 'tcp[tcpflags] & tcp-rst != 0'
# 看哪些会话有 RST
tshark -r /tmp/svr.pcap -Y 'tcp.flags.reset == 1' \
-T fields -e tcp.stream -e ip.src -e ip.dst | sort -u
tcp.stream 是 Wireshark 给每个 TCP 会话的整数 ID。找到出问题的 stream 号
(比如 7):
tshark -r /tmp/svr.pcap -Y 'tcp.stream == 7' -V | less
4. 用 Wireshark 看
scp server:/tmp/svr.pcap .
wireshark svr.pcap
经验流程:
- Statistics → Conversations → TCP,看哪些会话异常短或有 RST
- 右键问题会话 Follow → TCP Stream:看应用层 payload,能判断 RST
是发生在哪条请求 / 哪个字节边界 - Expert Information(左下角的⚠图标):Wireshark 自动标注的
异常(previous segment lost, dup ACK, RST 等)
5. RST 的常见根因
| 现象 | 根因 |
|---|---|
| 服务端发的 RST,紧跟在 FIN 之后 | 应用没读完 socket 缓冲就 close(HTTP body 没消费) |
| 客户端发的 RST,应用层没异常 | 客户端 OS RST:socket 被强制回收(fd 泄露后被 GC) |
| 中间设备发的 RST,TTL 远小于真实端 | 防火墙 / 流量清洗设备主动断 |
| 握手后立刻 RST | TCP wrappers / hostsdeny;或对端只接受 IPv4 而你发的 IPv6 |
| 大块上传中途 RST | LB 的 buffer overflow / 限流;或 MTU 不匹配(Path MTU Black Hole) |
6. MTU 问题的快速验证
如果怀疑 MTU:
# 强制最大 1500 - 28 = 1472 字节 payload,不允许分片
ping -M do -s 1472 <server>
# 二分缩小直到能通
ping -M do -s 1400 <server>
ping ... fragmentation needed 就是被某段链路要求分片但你设了 DF(不分片)。
通常出现在 PPPoE / VPN / 部分隧道场景。
7. 持续抓包(环形缓冲)
排查间歇性问题时,连续抓不停但不要把磁盘塞满:
sudo tcpdump -i any -s 0 \
-w /tmp/sniff-%Y%m%d-%H%M%S.pcap \
-G 600 \
-W 24 \
'tcp port 8080'
-G 600 每 10 分钟切新文件;-W 24 最多保留 24 个,循环覆盖。
踩过的坑
- 抓包文件别忘了清理 ——
-s 0在繁忙服务上一小时能写 GB 级。 - tshark
-Y是显示过滤器(capture 后筛选),-f是 capture 过滤器
(抓的时候用)。语法不一样,别混。-Y 'tcp.port == 8080'vs
-f 'tcp port 8080'。 - TLS 流量看不到明文,配合 SSLKEYLOGFILE 让浏览器/curl 把会话 key 落地,
Wireshark 用这个 key 文件就能解密(Edit → Preferences → Protocols → TLS)。 - 抓本机环回流量在 Linux 上需要
-i lo,-i any偶尔会漏。
登录后参与评论。