Wireshark 抓包分析入门¶
Fiddler/Charles 看应用层,Wireshark 看传输层与网络层。当接口"根本没发出去""连接建不起来""偶发超时但服务端没日志"时,只有它能给出证据。
一、先确定抓包点¶
抓错位置,后面全白费。
| 现象 | 抓哪里 | 说明 |
|---|---|---|
| 浏览器请求失败 | 客户端网卡 | 能看到 SYN 有没有发出 |
| 本机服务(localhost) | Loopback 网卡 | Windows 用 Npcap 的 Adapter for loopback traffic capture,Linux 用 lo |
| 服务端偶发超时 | 服务端 tcpdump |
区分"没收到"与"收到了没回" |
| 网关后、LB 前 | 交换机镜像口 / SPAN | 判断丢包发生在哪一跳 |
| 容器内服务 | 宿主机 veth 或容器内抓 |
注意 NAT 后地址变化 |
Windows 安装 Npcap 时要勾选 "Support loopback traffic capture",否则 127.0.0.1 抓不到。
# Linux 服务端抓包(生产慎用,限制体积与时长)
sudo tcpdump -i any -s 0 -w /tmp/cap.pcapng 'tcp port 8080 and host 10.0.0.5' -C 100 -W 5
参数含义:
-s 0:抓完整包,不截断(默认 262144 在现代版本已是全量,但显式写更稳)-C 100 -W 5:每个文件 100MB,最多 5 个滚动-i any:Linux cooked capture,能同时看多网卡;只关心单网卡时指定eth0
二、捕获过滤器 vs 显示过滤器¶
| 类型 | 位置 | 语法 | 作用 |
|---|---|---|---|
| 捕获过滤器(BPF) | 抓包前 | tcp port 443 and host 10.0.0.5 |
减少文件体积,抓不到就永远没有 |
| 显示过滤器 | 抓包后 | tls.handshake.extensions_server_name contains "api" |
不影响抓包,只影响视图 |
捕获过滤器写错,包就永远丢了,排查阶段建议只按 host 粗过滤,甚至不过滤。
三、显示过滤器速查¶
# 连接与握手
tcp.flags.syn == 1 && tcp.flags.ack == 0 # 所有 SYN
tcp.flags.reset == 1 # 所有 RST
tcp.analysis.retransmission # 重传
tcp.analysis.duplicate_ack # 重复 ACK
tcp.analysis.zero_window # 接收窗口为 0
tcp.analysis.window_full # 发送方窗口满
tcp.analysis.initial_rtt # 握手 RTT
# 应用层
http.request.method == "POST"
http.response.code >= 500
http.time > 1 # 应用处理超过 1 秒
http.request.uri contains "/api/order"
http.content_type contains "json"
# TLS / DNS
tls.handshake.type == 1 # ClientHello
tls.handshake.extensions_server_name # SNI
tls.alert_message # 握手/解密告警
dns.qry.name contains "api.example.com"
dns.flags.rcode != 0 # DNS 解析失败
# 组合
ip.addr == 10.0.0.5 && tcp.port == 8080 && http
frame contains "订单号"
tcp.analysis.* 这些字段需要 Wireshark 开启 TCP 分析(默认开启)。如果全是灰色不可用,检查 Analyze → Enabled Protocols → TCP。
四、TCP 基础:只看四个点¶
4.1 三次握手¶
Client → Server SYN seq=0 options: MSS=1460, SACK_PERM, WS=128
Server → Client SYN,ACK seq=0 ack=1 options: MSS=1440, SACK_PERM, WS=64
Client → Server ACK seq=1 ack=1
看三件事:
- MSS 协商:两端取小值。若中间有 VPN/隧道,MSS 变小会显著影响大请求。
- Window Scale:没有它,窗口最大 64KB,高延迟链路吞吐上不去。
- 握手耗时:
tcp.analysis.initial_rtt就是一次 RTT,跨地域 30~80ms 很常见,直接影响 TPS。
4.2 四次挥手与 RST¶
真正麻烦的是 RST:
- 服务端返回 RST:端口没监听、连接被防火墙重置、keep-alive 连接已被服务端关闭但客户端还在复用。
- 客户端发 RST:应用崩溃、连接池主动关闭。
4.3 序号与重传¶
Frame 120: seq=1000 len=1460
Frame 121: seq=2460 len=1460
Frame 122: seq=1000 len=1460 ← tcp.analysis.retransmission
重传间隔通常是 1s、3s、7s(指数退避)。看到连续重传,优先怀疑丢包或服务端未及时 ACK,而不是应用慢。
4.4 零窗口¶
tcp.analysis.zero_window 表示接收方缓冲区满了,发送方必须停。根因通常是应用读得太慢(GC、锁、慢 SQL),不是网络。这时看服务端线程栈比看包更有效。
五、RT 分解:把"慢"拆成四段¶
一个 HTTPS 请求的耗时:
在 Wireshark 里逐段读时间戳:
dns.qry.name == "api.example.com"→ 看 Query 与 Response 的时间差;- 找到对应 IP 的
SYN与SYN,ACK→ 差值即 TCP 握手; tls.handshake.type == 1(ClientHello)到type == 2(ServerHello)再到Finished→ TLS 握手;http.request到http.response的第一帧 → TTFB;- 最后一帧 DATA 到连接空闲 → 传输时间。
用
Frame → Time Display Format → Seconds Since Previous Displayed Packet可以快速看相邻包间隔。更精确的做法是Statistics → Conversations按流看 duration。
六、五个真实故障的定位过程¶
6.1 连接超时:SYN 发出但没有 SYN,ACK¶
No. 1 10.0.0.5 → 10.0.0.9 SYN
No. 2 10.0.0.5 → 10.0.0.9 SYN (1.0s 后重传)
No. 3 10.0.0.5 → 10.0.0.9 SYN (3.0s 后重传)
判定:
- 只有 SYN、无回应 → 中间防火墙丢包、安全组未放行、服务未监听(但服务未监听通常回 RST)。
- 有 RST 立即返回 → 端口未开或 LB 后端全挂。
- 服务端同时抓包:服务端能看到 SYN → 问题在回程或被本机防火墙丢;看不到 → 问题在去程链路。
6.2 TLS 握手失败¶
ClientHello (supported_versions: TLS 1.3, cipher_suites: ...)
Alert (Level: Fatal, Description: Protocol Version)
或:
Protocol Version:客户端与服务端没有交集,常见于老客户端/新服务端强制 TLS1.2+。Handshake Failure:没有共同 cipher suite,或客户端证书缺失(mTLS)。Unknown CA:客户端不信任服务端证书链(自签、缺中间证书)。
用 openssl 交叉验证:
openssl s_client -connect api.example.com:443 -servername api.example.com -tls1_2 </dev/null
openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>&1 | openssl x509 -noout -dates -subject -issuer
6.3 偶发 502:keep-alive 复用到了已关闭的连接¶
Frame 500: GET /api/order HTTP/1.1 (复用连接)
Frame 501: 服务端 → 客户端 FIN,ACK
Frame 502: 客户端 → 服务端 GET /api/order ← 发到了已关闭的连接
Frame 503: 服务端 → 客户端 RST
根因:LB 的空闲超时(如 60s)短于客户端连接池的 keep-alive(如 90s)。客户端复用了服务端已关闭的连接。
修复:
- 客户端 keep-alive < LB idle timeout(如 50s);
- 开启 TCP keepalive;
- 对幂等请求做一次重试。
这类问题在应用日志里只看到"connection reset",只有抓包能看清顺序。
6.4 大 POST 卡住:MTU 与分片¶
Frame 1: POST /upload len=1460
...
Frame N: 服务端无响应
ICMP: Destination Unreachable (Fragmentation needed, MTU 1400)
判定:请求体超过路径 MTU 且 DF 位被设置,中间设备不回 ICMP 或 ICMP 被过滤 → 黑洞。
# 探测路径 MTU(Linux)
ping -M do -s 1472 api.example.com # 1472 + 28 = 1500
ping -M do -s 1400 api.example.com
修复:调小接口 MTU/MSS clamp,或在应用层分片上传。
6.5 重传风暴:丢包还是服务端慢¶
- 重传 + dup ack + 窗口正常 → 链路丢包(看
Statistics → TCP Stream Graphs → Time-Sequence (tcptrace))。 - 重传 + 零窗口 → 接收端应用慢。
- 只有 dup ack 没有重传 → 对端在等缺失段,可能也是丢包。
Statistics → TCP Stream Graphs → Throughput 能看到吞吐随时间的变化,丢包会表现为锯齿。
七、解密 HTTPS:SSLKEYLOGFILE¶
Wireshark 不能"破解"TLS,但可以用客户端导出的密钥日志解密。
# 让 curl / Chrome / Firefox 导出握手密钥
export SSLKEYLOGFILE=/tmp/sslkey.log
curl https://api.example.com/health
Wireshark 配置:
之后同一会话的流量会自动解密成 HTTP/2 或 HTTP/1.1。
限制:
- 必须在抓包前设置环境变量,事后无法补;
- TLS 1.3 同样支持(key log 里包含 handshake secrets),但需要 Wireshark 3.0+;
- Java 应用需要
-Djavax.net.ssl.keyStore之外的方式:JDK 不支持 SSLKEYLOGFILE,只能改代码或使用jSSLKeyLogagent; - 移动 App 需要可调试包 + 注入,通常改用 Fiddler/Burp 代理。
八、HTTP/2 与 WebSocket¶
8.1 HTTP/2¶
Wireshark 显示 HTTP2,需要看:
HEADERS帧里的:method、:path、:authorityDATA帧的 stream id(同一连接多路复用)SETTINGS、WINDOW_UPDATE、RST_STREAM
常见问题:RST_STREAM 表示单个流被取消(超时、客户端主动取消),连接本身没断。只看 TCP 层会误判为"没断"。
8.2 WebSocket¶
之后是 WebSocket 帧,Follow → TCP Stream 仍能看到原始文本。
九、导出与命令行统计¶
9.1 导出对象¶
9.2 tshark 批量分析¶
# 列出所有 5xx 请求
tshark -r cap.pcapng -Y "http.response.code >= 500" \
-T fields -e frame.time_relative -e ip.src -e http.request.uri
# 统计每个域名的请求数
tshark -r cap.pcapng -Y "http.request" -T fields -e http.host \
| sort | uniq -c | sort -rn | head
# 统计重传次数
tshark -r cap.pcapng -Y "tcp.analysis.retransmission" -T fields -e ip.src \
| sort | uniq -c
9.3 关键统计¶
Statistics → Conversations # 每条流的字节数、时长、包数
Statistics → HTTP → Requests # 请求分布
Statistics → Service Response Time → HTTP # 各 URI 的响应时间
Statistics → TCP Stream Graphs # 吞吐、往返时间、窗口
Service Response Time 能按 URI 聚合,比逐条看快得多。
十、常见误区¶
- 在客户端抓包判断"服务端没收到":只能证明包发出去了,服务端是否收到必须在服务端抓。
- 捕获过滤器写得过窄:排查时漏掉 DNS、ICMP、重传。
- 把 RST 当成业务错误:RST 是连接层,应用日志往往没有记录。
- 看到重传就怪网络:零窗口导致的停顿是应用慢。
- 忽略时间基准:客户端与服务端时钟不同步,跨机对比必须先校时(NTP)。
- 抓包文件过大:生产上用
-C/-W滚动,先粗过滤再细看。
十一、检查清单¶
- 抓包点选对(客户端/服务端/loopback)
- 已复现问题并记录了准确时间点
- 捕获过滤器尽量宽,显示过滤器再收窄
- 检查 SYN 是否有回应、是否有 RST
- 检查 TLS alert 与证书链
- 用
tcp.analysis.*看过重传、dup ack、零窗口 - RT 已按 DNS/TCP/TLS/TTFB 分段
- 需要看明文时已提前设置 SSLKEYLOGFILE
- 结论有双向抓包或服务端日志佐证