29、网络调试与抓包:tcpdump使用、Wireshark分析、常见问题排查
网络编程这东西,写代码只占一半功夫。另一半,说白了就是跟数据包打交道。
你代码写得再漂亮,一跑起来发现连不上、收不到数据、或者莫名其妙断开了——这时候就得靠抓包工具来破案。我个人习惯是:先怀疑网络,再怀疑代码。这个顺序帮我省了无数时间。
核心观点:抓包不是玄学,是科学。你看到的每一个包,都在告诉你真相。
29.1 tcpdump:命令行下的“网络显微镜”
tcpdump 是我在服务器上排查问题的第一选择。为什么?因为服务器通常没有图形界面,而且 tcpdump 轻量、高效、几乎零依赖。
29.1.1 基本用法
先来几个最常用的命令,我几乎每天都会用到:
# 抓取 eth0 网卡的所有流量
tcpdump -i eth0
# 只抓 10 个包,然后退出
tcpdump -i eth0 -c 10
# 显示更详细的信息(协议头、时间戳等)
tcpdump -i eth0 -v
# 不进行 DNS 解析,显示 IP 地址(推荐)
tcpdump -i eth0 -n
为什么推荐加 -n? 因为 DNS 解析会拖慢抓包速度,而且有时候 DNS 本身就有问题,反而干扰你判断。我遇到过好几次,加了 -n 之后问题立刻清晰了。
29.1.2 过滤表达式
不设过滤的 tcpdump 就是噪音。你想想看,生产服务器上一秒钟几千个包,你不过滤根本看不下去。
| 过滤条件 | 示例 | 说明 |
|---|---|---|
| 按主机 | host 192.168.1.100 |
只抓与某 IP 通信的包 |
| 按端口 | port 8080 |
只抓某端口的流量 |
| 按协议 | tcp 或 udp |
只抓 TCP 或 UDP 包 |
| 组合条件 | tcp and port 80 and host 10.0.0.1 |
多条件组合 |
| 抓 SYN 包 | 'tcp[tcpflags] & tcp-syn != 0' |
只抓握手阶段的 SYN 包 |
我的小技巧:先用 -c 100 抓少量包看看流量特征,确认过滤条件正确后,再放开抓。不然你可能抓了一堆没用的数据。
29.1.3 保存与读取
抓包文件可以保存下来慢慢分析,或者发给同事看:
# 保存到文件
tcpdump -i eth0 -w capture.pcap
# 读取文件
tcpdump -r capture.pcap
# 读取时也支持过滤
tcpdump -r capture.pcap port 443
我曾经在生产环境上抓了一个小时的包,文件有 2GB 多。后来用过滤条件一筛,真正有问题的包就几十个。所以 抓包要广,分析要精。
29.2 Wireshark:图形化的“包解剖师”
tcpdump 适合快速定位,但真要深入分析协议细节,我推荐 Wireshark。它能把每个包的每个字段都拆开给你看。
29.2.1 核心功能
- 协议解析:自动识别 HTTP、TCP、UDP、DNS 等上百种协议
- 着色规则:不同颜色代表不同协议或异常,一眼就能看出问题
- 跟踪流:右键点击一个 TCP 包,选择“Follow TCP Stream”,就能看到完整的会话内容
- 统计工具:可以看 IO 图表、对话统计、端点统计等
29.2.2 常用过滤语法
Wireshark 的过滤语法比 tcpdump 更直观:
# 只显示 HTTP 请求
http.request
# 只显示某个 IP 的流量
ip.addr == 192.168.1.1
# 只显示 TCP 端口 80
tcp.port == 80
# 显示重传包
tcp.analysis.retransmission
# 显示 RST 包(连接被重置)
tcp.flags.reset == 1
注意:Wireshark 的显示过滤器和捕获过滤器是两回事。捕获过滤器在抓包时就用,语法类似 tcpdump;显示过滤器是在抓完包之后筛选用的,语法更丰富。别搞混了。
29.3 常见问题排查实战
下面这几个场景,是我在实际项目中反复遇到的。每个都对应一个典型的抓包特征。
29.3.1 场景一:连接超时
现象:客户端 connect 返回 -1,errno 是 ETIMEDOUT。
抓包特征:只看到客户端发 SYN,没有 SYN-ACK 回来。客户端重试几次后放弃。
原因分析:
- 服务器没启动监听
- 防火墙拦截了入站 SYN
- 服务器负载过高,内核来不及响应
排查思路:在服务器上抓包,看有没有收到 SYN。如果收到了但没回 SYN-ACK,那就是应用层或内核的问题。如果根本没收到,那就是网络路径的问题。
29.3.2 场景二:连接被重置
现象:客户端收到 RST 包,连接直接断开。
抓包特征:看到 RST 标志位为 1 的包。
原因分析:
- 服务器主动关闭了连接(比如调用了 close 或 shutdown)
- 端口未监听,内核直接回 RST
- 防火墙发送了 RST(常见于某些安全设备)
我曾经遇到过:一个客户说他们的客户端总是连不上我们的服务。我抓包一看,每次 SYN 发出去,对面立刻回 RST。查了半天,发现是客户那边的防火墙把我们的 IP 加入了黑名单。嗯,这种问题代码层面根本解决不了。
29.3.3 场景三:数据发送失败
现象:send 返回 -1,或者 send 成功但对方没收到。
抓包特征:
- 发送端发了数据,但接收端没回 ACK
- 或者看到大量 TCP 重传(Retransmission)
- 接收端窗口为 0(Zero Window),发送端被阻塞
原因分析:
- 接收端应用层没及时 recv,导致接收缓冲区满
- 网络丢包严重
- 发送端发送速度太快,超出了接收端的处理能力
我的建议:看到 Zero Window 不要慌。这其实是 TCP 流控在正常工作。真正的问题在于 Zero Window 持续太久,或者频繁出现。这时候应该检查接收端的应用逻辑,是不是 recv 循环写得有问题。
29.4 本章知识体系
下面这张图,是我自己总结的抓包排查流程。每次遇到网络问题,我就按这个思路走一遍:
29.5 避坑指南
最后分享几个我踩过的坑,希望能帮你少走弯路:
- 不要在高峰时段在生产环境抓包:我曾经有一次在业务高峰期抓包,结果 tcpdump 本身消耗了大量 CPU,导致服务响应变慢。后来我学乖了,要么在低峰期抓,要么用
-c限制包数量。 - 抓包文件要及时清理:pcap 文件很容易膨胀。有一次我忘了关 tcpdump,第二天发现磁盘满了。现在我的脚本里都会加一个自动清理的逻辑。
- 注意抓包权限:tcpdump 需要 root 权限或者 CAP_NET_RAW 能力。如果你用普通用户跑,会报错说打不开原始套接字。
- Wireshark 的着色规则不是万能的:它标记为“可疑”的包,不一定就是问题。反过来,没标记的也不一定就正常。还是要靠自己的分析。
网络调试这件事,说白了就是“看包说话”。你抓的包越多,经验就越丰富。刚开始可能会觉得眼花缭乱,但只要你坚持用 tcpdump 和 Wireshark 去验证每一个猜测,慢慢地你就能一眼看出问题所在。
公众号:蓝海资料掘金营,微信deep3321