日志显示请求发出去了,对方却说没收到;接口偶发超时,没有任何报错;明明连上了,数据却对不上。这类「看不见的传输层问题」,用再多的应用日志也定位不了,只能靠抓包------把网线上真正流动的字节一个一个抓下来看。这一篇讲透 Linux 抓包三件套:tcpdump 命令行抓、tshark 命令行分析、Wireshark 图形化细看,从语法到实战过滤器一次讲清。
一、抓包能解决什么
抓包是网络排障的「终极手段」,因为它能回答其他工具答不了的问题:
- 请求到底发出去了没有?(还是应用根本没发)
- 对方回了什么?(RST?超时?错误码?)
- 重传、乱序、丢包发生在哪一段?
- TLS 握手卡在哪一步?
- 数据内容和长度是否和服务端预期一致?
一句话:抓包是站在「网线视角」看问题,屏蔽了应用层的所有猜测。
二、tcpdump:命令行抓包主力
tcpdump 几乎每台 Linux 都自带或可秒装,是服务器抓包的绝对主力。
安装
sudo apt install tcpdump -y # Ubuntu
sudo dnf install tcpdump -y # Rocky/CentOS
语法格式
tcpdump [选项] [过滤表达式]
常用参数
| 参数 | 说明 |
|---|---|
-i 网卡 |
指定网卡(any 表示所有) |
-nn |
不解析主机名和端口名(保持数字,快且准) |
-c N |
抓 N 个包后停止 |
-w 文件 |
保存为 pcap 文件(供 Wireshark 分析) |
-r 文件 |
读取 pcap 文件 |
-s 长度 |
抓取每个包的前 N 字节(-s0 抓全部) |
-A |
以 ASCII 显示内容(看明文 HTTP/Redis) |
-X |
同时显示十六进制和 ASCII |
-v/-vv/-vvv |
越来越详细的输出 |
-e |
显示链路层(MAC)信息 |
-l |
行缓冲,配合管道实时看 |
基础示例
看某网卡上的所有流量:
sudo tcpdump -i eth0 -nn
10:30:01.123 IP 192.168.1.10.54321 > 93.184.216.34.80: Flags [S], seq 123456, win 64240, length 0
10:30:01.145 IP 93.184.216.34.80 > 192.168.1.10.54321: Flags [S.], seq 654321, ack 123457, win 65535, length 0
抓 100 个包就停,保持数字显示:
sudo tcpdump -i eth0 -nn -c 100
让 tcpdump 抓包不影响生产
抓包会占用 CPU 和磁盘,生产环境务必加限制:
# 只抓 1000 个包、每包前 96 字节、写入文件
sudo tcpdump -i eth0 -nn -c 1000 -s 96 -w /tmp/cap.pcap
存成 pcap 文件后,可以下载到本地用 Wireshark 慢慢分析,避免在服务器上做重活。
三、过滤器(BPF):只抓你关心的
无过滤抓包等于大海捞针。tcpdump 用 BPF(Berkeley Packet Filter) 语法做过滤,核心是「类型 + 方向 + 协议/端口」。
基础过滤
# 按主机
tcpdump host 192.168.1.100
# 按源/目的
tcpdump src 192.168.1.100
tcpdump dst 192.168.1.100
# 按端口
tcpdump port 80
tcpdump src port 443
# 按协议
tcpdump tcp
tcpdump udp
tcpdump icmp
组合过滤(and / or / not)
# 与某主机 80 端口的通信
tcpdump -nn host 192.168.1.100 and port 80
# 排除 SSH,避免抓到自己
tcpdump -nn not port 22
# 某网段访问 443
tcpdump -nn net 192.168.1.0/24 and port 443
# 两个条件任一
tcpdump -nn port 80 or port 443
进阶:按 TCP 标志位过滤
# 只抓 SYN 包(看连接建立)
tcpdump -nn 'tcp[tcpflags] & tcp-syn != 0'
# 只抓 RST 包(看连接被拒)
tcpdump -nn 'tcp[tcpflags] & tcp-rst != 0'
# 抓 FIN(看连接关闭)
tcpdump -nn 'tcp[tcpflags] & tcp-fin != 0'
按包大小过滤(找大包、异常包)
tcpdump -nn 'greater 1000' # 大于 1000 字节
tcpdump -nn 'less 100' # 小于 100 字节
四、tcpdump 实战场景
场景 1:抓 HTTP 请求内容
sudo tcpdump -i eth0 -nn -A -s0 port 80
-A 显示 ASCII 内容,能看到明文 HTTP 请求头和响应,适合排查「请求发没发、返回什么」。
场景 2:抓 Redis/Memcached 等明文协议
sudo tcpdump -i eth0 -nn -A -s0 port 6379
能看到 Redis 命令原文,快速确认客户端发了什么。
场景 3:排查连接超时
# 抓 SYN 包,看有没有回 SYN-ACK
sudo tcpdump -nn -c 20 'tcp[tcpflags] & tcp-syn != 0 and host 10.0.0.5'
- 有 SYN 没 SYN-ACK → 对方没回(防火墙 DROP 或服务没监听)
- 有 SYN 有 RST → 对方端口没开
- 有 SYN 有 SYN-ACK 没 ACK → 客户端侧问题
场景 4:定位重传
sudo tcpdump -nn -i eth0 -w /tmp/retrans.pcap port 443
下载后用 Wireshark 看 tcp.analysis.retransmission 过滤,或直接用 tshark 统计。
场景 5:抓特定 IP 的 DNS 查询
sudo tcpdump -nn -i any port 53 and host 192.168.1.10
五、tshark:命令行的 Wireshark
tshark 是 Wireshark 的命令行版,不需要 GUI,能在服务器上直接分析 pcap,还能统计。
安装
sudo apt install tshark -y # Ubuntu
sudo dnf install wireshark-cli -y # Rocky/CentOS
常用参数
| 参数 | 说明 |
|---|---|
-i 网卡 |
实时抓包 |
-r 文件 |
读 pcap 文件 |
-Y 过滤 |
显示过滤(Wireshark 语法) |
-T fields -e 字段 |
输出指定字段 |
-z 统计 |
做统计(如 -z io,stat,1) |
-V |
显示包的全部协议树 |
示例
读取 pcap 并按条件过滤:
tshark -r /tmp/cap.pcap -Y "http.request" -T fields -e http.host -e http.request.uri
api.example.com /v1/users
api.example.com /v1/orders
统计重传:
tshark -r /tmp/cap.pcap -Y "tcp.analysis.retransmission" | wc -l
看每秒包数:
tshark -r /tmp/cap.pcap -z io,stat,1
统计 TCP 连接耗时:
tshark -r /tmp/cap.pcap -Y "tcp.flags.syn==1 && tcp.flags.ack==0" -T fields -e ip.src -e ip.dst -e tcp.dstport
tshark 的定位
- 服务器无 GUI → 用
tshark命令行抓和初步分析。 - 需要深度交互 →
tcpdump/tshark抓成 pcap,下载到本地用Wireshark。
六、Wireshark:图形化精细分析
Wireshark 是抓包分析的黄金标准,图形界面、协议解码、流量统计一应俱全。服务器上一般不装,而是在本地分析别处抓来的 pcap。
基本工作流
tcpdump -w在服务器抓包。- 下载 pcap 到本地。
- Wireshark 打开,用显示过滤器缩小范围。
常用显示过滤器
| 过滤器 | 作用 |
|---|---|
ip.addr == 192.168.1.100 |
某 IP 相关 |
tcp.port == 80 |
某端口 |
http |
所有 HTTP |
http.request.method == "POST" |
POST 请求 |
tcp.analysis.retransmission |
重传包 |
tcp.analysis.zero_window |
零窗口(接收方处理不过来) |
tcp.flags.reset == 1 |
RST 包 |
dns |
DNS 查询 |
tls.handshake.type == 1 |
TLS ClientHello |
三个最有用的功能
- Follow TCP Stream(右键 → Follow → TCP Stream):把一条连接的完整对话拼出来,看 HTTP 请求响应最直观。
- Statistics → Conversations:按会话看流量排名,找占带宽的元凶。
- Expert Information(分析 → 专家信息):自动标出重传、丢包、乱序等异常。
七、抓包分析的通用技巧
- 先缩小范围:用过滤器抓「关注的 IP + 端口」,别抓全量。
- pcap 会很大 :加
-c限包数、-s限长度,别把磁盘写满。 - 对时间:抓包时间戳和应用日志时间对齐,才能把「日志报错」和「网络包」对应起来。
- 看序列号:TCP 序列号能揭示重传、乱序、丢包。
- 看 RTT :
tcp.analysis.ack_rtt反映真实往返延迟。 - 关注标志位:SYN/SYN-ACK/ACK/FIN/RST 组合能还原连接的生命周期。
八、⚠️ 常见错误
- 抓包不加限制写满磁盘 。生产抓包必须
-c+-s+-w,或限制时间。 - 抓包不过滤抓到一堆无关流量。务必用 BPF 过滤到具体 IP/端口。
- 在错误的网卡上抓 。多网卡机器要选对
-i,或用any。 - 忘了权限 。抓包需要 root 或
CAP_NET_RAW,普通用户会报permission denied。 - 看到重传就以为网络坏。少量重传正常,大量重传(>1%)才说明链路有问题。
- 忽略抓包本身的影响 。高流量下抓包会掉包,
tcpdump报packets dropped by kernel时抓到的数据不完整,要调大 buffer(-B)或减少过滤范围。 - 加密流量看不懂就放弃 。TLS 流量看不到内容,但握手过程、RST、重传、时延仍可分析,这些往往才是问题所在。
- 在容器里抓宿主网卡的包。容器网络要进对应的 network namespace 抓。
九、原理探究:一次三次握手的抓包实录
抓包最有价值的能力是「读懂连接的生命周期」。用一次 TCP 三次握手 + 数据传输 + 四次挥手为例:
三次握手
1 10.0.0.5.54321 > 10.0.0.9.80: Flags [S], seq 1000, win 64240
2 10.0.0.9.80 > 10.0.0.5.54321: Flags [S.], seq 5000, ack 1001, win 65535
3 10.0.0.5.54321 > 10.0.0.9.80: Flags [.], ack 5001, win 64240
- 包 1:客户端发
SYN,seq=1000 - 包 2:服务端回
SYN+ACK(S.),ack=1001(1000+1),seq=5000 - 包 3:客户端回
ACK(.),ack=5001(5000+1)
记住规律:ack = 对方 seq + 1(SYN 和 FIN 各占一个序号)。
数据传输
4 10.0.0.5.54321 > 10.0.0.9.80: Flags [P.], seq 1001:1501, ack 5001, length 500
5 10.0.0.9.80 > 10.0.0.5.54321: Flags [.], ack 1501, win 65535
- 包 4:客户端发 500 字节数据(
P.表示 PSH+ACK),seq 1001~1501 - 包 5:服务端 ACK,确认收到 1501
四次挥手
6 10.0.0.5.54321 > 10.0.0.9.80: Flags [F.], seq 1501, ack 5001
7 10.0.0.9.80 > 10.0.0.5.54321: Flags [.], ack 1502
8 10.0.0.9.80 > 10.0.0.5.54321: Flags [F.], seq 5001, ack 1502
9 10.0.0.5.54321 > 10.0.0.9.80: Flags [.], ack 5002
- 包 6/7:客户端发
FIN,服务端ACK - 包 8/9:服务端发
FIN,客户端ACK
从抓包能看出什么异常
| 现象 | 抓包特征 | 含义 |
|---|---|---|
| 连接被拒 | SYN → RST | 端口没开 |
| 连接超时 | SYN →(无回应) | 防火墙 DROP 或不可达 |
| 服务端处理慢 | 收到请求后长时间无 ACK/响应 | 应用处理慢 |
| 网络丢包 | 重复的 seq、retransmission |
链路丢包 |
| 接收方满 | zero_window |
接收方来不及处理 |
| 半开连接 | 大量 SYN 无后续 | SYN Flood 或扫描 |
抓包的底层原理
tcpdump 使用 libpcap 库,通过内核的 AF_PACKET 套接字 直接从数据链路层复制数据包。这就是为什么它能抓到「网线上真实的字节」------它绕过了 TCP/IP 协议栈的处理,直接看原始帧。也正因为抓的是链路层,它能看到 TCP/IP 层不会暴露的问题(如 MAC 冲突、ARP 异常)。
理解抓包的层次,就知道它的边界:在容器/虚拟化环境里,数据包会经过多张虚拟网卡,要在正确的 namespace 和网卡上抓,才能看到你要的那段流量。
十、抓包速查表
# 快速抓 HTTP 内容
sudo tcpdump -i eth0 -nn -A -s0 port 80
# 抓包存文件
sudo tcpdump -i eth0 -nn -c 1000 -s0 -w /tmp/cap.pcap
# 抓 SYN/RST 诊断连接
sudo tcpdump -nn 'tcp[tcpflags] & (tcp-syn|tcp-rst) != 0'
# 读文件 + 过滤(tshark)
tshark -r cap.pcap -Y "http.request" -T fields -e http.host -e http.request.uri
# 统计重传
tshark -r cap.pcap -Y "tcp.analysis.retransmission" | wc -l
# 抓指定主机+端口
sudo tcpdump -nn host 10.0.0.5 and port 443 -w /tmp/tls.pcap
抓包是「用真相终结猜测」的手段。记住主线:tcpdump 抓、BPF 过滤、tshark 命令行分析、Wireshark 精细解读。掌握了抓包,你就拥有了看穿网络问题的「透视眼」,任何「明明发出去了对方说没收到」的扯皮都能一锤定音。