排查网络问题,日志看不出来、监控指标也正常,最后往往得靠抓包。数据包在网络里到底长什么样、谁先发的、有没有丢、有没有被重置,抓一份 pcap 一看就清楚。而 Linux 上最通用、几乎每台机器都有的抓包工具就是 tcpdump。
这篇文章从安装讲起,把常用参数、过滤表达式、几组实战场景、配合 Wireshark/tshark 分析的方法,以及权限和性能注意事项一次讲清楚。目标是让你遇到"服务不通""连接重置""响应慢"这类问题时,能立刻抓出有用的包,而不是抓一大堆看不过来。
一、安装 tcpdump
大多数发行版可以直接从仓库装:
# RHEL / CentOS / Rocky / AlmaLinux 7(yum)
sudo yum install -y tcpdump
# RHEL / CentOS / Rocky / AlmaLinux 8/9(dnf)
sudo dnf install -y tcpdump
# Debian / Ubuntu
sudo apt update && sudo apt install -y tcpdump
# 验证
tcpdump --version
如果机器不能上网,也可以从发行版镜像站下载对应的 rpm/deb 包本地安装。抓包要读原始套接字,需要 root 权限,或者给二进制文件授予 CAP_NET_RAW/CAP_NET_ADMIN 能力。
二、先认清网卡和基本用法
抓包第一步是选对网卡。机器上可能有物理网卡、docker0、隧道接口等,抓错网卡什么都看不到。
# 查看可用接口(-D 列出接口)
tcpdump -D
# 查看系统网卡
ip link show
tcpdump -D 的输出会给出接口编号和名称,比如 eth0、ens33、lo。用 -i 指定:
# 抓 eth0 上的流量,-nn 不解析主机名和端口名,-c 抓 10 个包后停止
sudo tcpdump -i eth0 -nn -c 10
# 抓所有接口(any)
sudo tcpdump -i any -nn -c 10
# 抓本地回环
sudo tcpdump -i lo -nn -c 10
不加 -i 时 tcpdump 会挑一个默认接口,不一定是你要的,所以养成显式指定 -i 的习惯。
怎么看 tcpdump 的输出
抓包容易,看懂才是关键。一行典型的 TCP 输出大概长这样:时间戳、源 IP.源端口、目的 IP.目标端口、TCP 标志、序号、确认号、窗口大小、长度。比如 10.0.0.5.52134 > 10.0.0.8.443: Flags [S], seq 12345, win 64240, length 0,意思是从 10.0.0.5 的 52134 端口发往 10.0.0.8 的 443 端口,标志位是 SYN,初始序号 12345,窗口 64240,没有携带数据。
几个核心要点记住就能读懂绝大多数包:
- 方向箭头:
>表示发出,<表示收到。看清是谁发的,是定位问题的第一步。 - 标志位:
[S]SYN 建连、[S.]SYN+ACK、[.]纯 ACK、[P.]带数据的 ACK、[F.]FIN 关闭、[R]RST 重置。方括号里有.表示 ACK 置位。 - 序号与确认号:默认显示的是相对序号(相对第一个包),加
-S显示绝对序号,分析重传和乱序时更有用。 - length:载荷长度,
length 0说明是纯控制包,没有应用数据。 - win:通告窗口大小,能侧面反映接收端缓冲区情况。
再看协议端口就能串起一条连接的故事:先 [S] 后 [S.] 再 [.],连接建立;中间大量 [P.] 是数据传输;出现 [F.] 是开始关闭;如果中途冒出一个 [R],说明连接被强制重置,往往就是故障点。理解了这套"读包语言",抓包才真正产生价值。
三、常用参数速查
| 参数 | 作用 | 说明 |
|---|---|---|
-i <接口> |
指定网卡 | any 表示所有接口 |
-nn |
不解析主机名和端口 | 更快,避免 DNS 反查干扰 |
-s0 |
抓完整包(snaplen 0) | 新版本默认就是全包 |
-c |
抓 N 个包后退出 | 避免无限抓 |
-w <文件> |
写入 pcap 文件 | 供后续分析 |
-r <文件> |
读取 pcap 文件 | 分析已抓的包 |
-A |
以 ASCII 显示载荷 | 看 HTTP 文本内容 |
-X |
十六进制 + ASCII 显示 | 看二进制内容 |
-v / -vv / -vvv |
显示更详细信息 | 看 TTL、校验等 |
-e |
显示链路层头 | 看 MAC 地址 |
-S |
显示 TCP 绝对序号 | 便于分析握手挥手 |
-t |
不显示时间戳 | 输出更简洁 |
-q |
精简输出 | 高流量下减少开销 |
-Z <用户> |
抓包后切换到指定用户 | 降低权限风险 |
提示:老版本 tcpdump 默认只抓 96 字节,导致看不到完整载荷,需要
-s0(或-s 65535)抓全包。较新版本默认已抓全,但写上-s0更保险。
四、过滤表达式:只抓有用的包
抓包最大的问题是量太大。过滤表达式(BPF 语法)是核心技能,掌握后抓包效率翻倍。
按主机过滤
# 源或目的为某 IP
sudo tcpdump -i eth0 -nn host 192.168.1.100
# 只要源 IP
sudo tcpdump -i eth0 -nn src 192.168.1.100
# 只要目的 IP
sudo tcpdump -i eth0 -nn dst 192.168.1.100
按端口过滤
# 某端口(源或目的)
sudo tcpdump -i eth0 -nn port 80
# 源端口
sudo tcpdump -i eth0 -nn src port 3306
# 目的端口
sudo tcpdump -i eth0 -nn dst port 443
# 端口范围
sudo tcpdump -i eth0 -nn portrange 8000-9000
按协议过滤
# 只看 TCP / UDP / ICMP
sudo tcpdump -i eth0 -nn tcp
sudo tcpdump -i eth0 -nn udp
sudo tcpdump -i eth0 -nn icmp
# 仅 IPv6
sudo tcpdump -i eth0 -nn ip6
逻辑组合
# and:同时满足
sudo tcpdump -i eth0 -nn 'host 192.168.1.100 and port 80'
# or:满足其一
sudo tcpdump -i eth0 -nn 'port 80 or port 443'
# not:排除
sudo tcpdump -i eth0 -nn 'host 10.0.0.5 and not port 22'
# 复杂组合:来自某网段访问 80 或 443 的 TCP 包
sudo tcpdump -i eth0 -nn 'tcp and src net 192.168.1.0/24 and (port 80 or port 443)'
注意:表达式里带括号、and/or 这类关键字时,整体用单引号包起来,避免被 shell 解释。
过滤表达式写得好不好,直接决定抓包效率。新手常见做法是只写 tcpdump -i eth0,结果满屏包刷个不停,关键信息淹没在噪声里。正确思路是先明确"我要看什么":是某台机器的问题,就写 host;是某个端口的问题,就写 port;是抓控制包还是数据包,就用 tcp[tcpflags] 进一步受限。一层层缩小范围,包的数量往往能从每秒几万降到每秒几条,问题一眼就能看出来。反过来,如果一开始过滤写得太死,也可能把关键的 ICMP 错误、RST 包漏掉,所以建议先用较宽松的条件确认有流量,再逐步收紧。
五、几个实战场景
场景一:抓某个服务的 TCP 握手和挥手
# 抓 443 端口的 SYN/FIN/RST,观察连接建立与释放
sudo tcpdump -i eth0 -nn -S 'tcp port 443 and (tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0)'
看输出:Flags [S] 是 SYN,[S.] 是 SYN+ACK,[.] 是 ACK,[F.] 是 FIN+ACK,[R] 是 RST,[P.] 是 PSH+ACK(带数据)。通过序号和标志就能还原握手挥手全过程。
场景二:抓 HTTP 请求内容
# 抓 80 端口并显示 ASCII 载荷,能看到请求行和响应头
sudo tcpdump -i eth0 -nn -A 'tcp port 80'
# 只抓 GET 请求
sudo tcpdump -i eth0 -nn -A 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420)'
注意 HTTPS 内容是加密的,-A 只能看到 TLS 握手记录,看不到真正的 HTTP 报文。要分析 HTTPS 内容需要密钥或采用其他手段。
场景三:抓指定 IP 之间的流量并保存成文件
# 抓 10.0.0.5 与 10.0.0.8 之间的流量,写入文件,最多抓 1000 个包
sudo tcpdump -i eth0 -nn -s0 -c 1000 -w /tmp/capture.pcap 'host 10.0.0.5 and host 10.0.0.8'
# 读取并查看
tcpdump -nn -r /tmp/capture.pcap -c 20
# 按端口再看
tcpdump -nn -r /tmp/capture.pcap 'tcp port 3306'
场景四:抓 RST 包定位连接重置
# 只抓带 RST 标志的包
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'
# 抓 RST 并显示详细信息,看是谁发出的
sudo tcpdump -i eth0 -nn -S 'tcp[tcpflags] & tcp-rst != 0' -vv
看 RST 的来源 IP 和目标端口,就能判断是服务端拒绝(端口没监听会直接回 RST)还是中间设备插了一脚。
场景五:抓 DNS 查询
# 抓 53 端口
sudo tcpdump -i eth0 -nn port 53
# 抓 DNS 查询,-vv 能看到查询的域名
sudo tcpdump -i eth0 -nn -vv port 53
六、配合 Wireshark / tshark 分析
tcpdump 擅长抓,Wireshark 擅长解析和可视化。最佳实践是:服务器上用 tcpdump 抓成 pcap,下载到本地用 Wireshark 打开。
# 服务器上抓包,限制大小防止占满磁盘
sudo tcpdump -i eth0 -nn -s0 -w /tmp/issue.pcap -C 100 -W 5 'host 10.0.0.8'
-C 100 表示每个文件最多 100 MB(1,000,000 字节),-W 5 表示保留 5 个文件循环覆盖,避免把磁盘写满。
如果想在服务器上直接分析,用 tshark(Wireshark 的命令行版):
# 安装(RHEL 系)
sudo dnf install -y wireshark-cli
# 安装(Debian/Ubuntu)——注意会弹出是否允许普通用户抓包的选项
sudo apt install -y tshark
# 用 tshark 读 pcap 并做统计
tshark -r /tmp/issue.pcap -q -z io,stat,1
# 统计 HTTP 请求
tshark -r /tmp/issue.pcap -Y http.request -T fields -e http.host -e http.request.uri
# 跟踪一条 TCP 流
tshark -r /tmp/issue.pcap -z follow,tcp,ascii,0
Wireshark 里最常用的几个功能:Follow TCP Stream(跟踪整条流)、Statistics → Conversations(看通信对端)、专家信息(自动提示重传、乱序、RST)。
七、权限与性能提示
权限:抓包要 root。长期让服务以 root 抓包不安全,可以用能力或让 tcpdump 抓完切换到普通用户:
# 给 tcpdump 授予抓包能力(避免每次 sudo)
sudo setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
# 抓包后切换身份
sudo tcpdump -i eth0 -Z nobody -w /tmp/x.pcap
性能:tcpdump 在高流量网卡上会消耗 CPU 并可能丢包(内核抓包缓冲不够)。几个缓解手段:
- 加过滤条件,只抓需要的包,别用
any全量抓。 - 用
-c限制包数、-C/-W限制文件大小,防止磁盘和内存被占满。 - 用
-q减少输出开销,用-w直接落盘而不是打印到终端。 - 提高抓包缓冲(
-B)以减少丢包:sudo tcpdump -i eth0 -B 4096 -w /tmp/x.pcap。
风险提示:抓包文件包含明文流量(如 HTTP 请求、登录凭据),属于敏感数据。不要在共享环境随意存放,分析完及时删除;涉及生产数据时注意脱敏与合规要求。高流量下长时间抓包可能影响业务,建议限时限量,并在非高峰期操作。
常见问题
Q:抓不到包是什么原因?
A:常见三类:网卡选错(用 tcpdump -D 确认)、过滤表达式写错(先用 -nn 不过滤试一下)、流量根本没走这台机器(比如经过交换机旁路、或走了别的网卡/隧道)。
Q:为什么抓到的包看不到内容?
A:可能是 HTTPS 加密(看不到明文 HTTP),也可能是 snaplen 太小没抓全包,加 -s0。用 -A 或 -X 看载荷。
Q:-nn 到底省了什么?
A:不加 -nn 时 tcpdump 会尝试把 IP 反查成主机名、把端口号转成服务名,每次都要查 DNS,既慢又可能产生额外流量,还可能因为反查超时而拖慢输出。排查问题时用 -nn 既快又清晰。
Q:抓包影响业务吗?
A:正确使用(加过滤、限数量、限时长)影响很小。无过滤、长时间、全量抓包会吃 CPU、内存和磁盘,极端情况下会丢包甚至影响业务,务必克制。
Q:怎么抓本机进程之间的通信?
A:用 -i lo 抓回环接口,因为本机进程互访走的是 lo,不经过物理网卡。
总结
- tcpdump 是 Linux 最通用的抓包工具,装好后用
-D认接口、-i指定网卡、-nn免解析、-s0抓全包、-c限数量。 - 过滤表达式是效率关键:
host、src/dst、port、portrange、tcp/udp/icmp,配合and/or/not组合,整体加单引号。 - 实战常用:抓握手挥手(
tcp[tcpflags] & (tcp-syn|tcp-fin))、抓 HTTP 内容(-A)、抓指定 IP 落盘(-w)、抓 RST 定位重置。 - 服务器抓包存成 pcap,下载到本地用 Wireshark 分析,或用 tshark 在服务器上直接统计与跟踪流。
- 抓包需 root,务必加过滤、限大小时长,注意抓包文件的敏感性和对业务的影响。
企业QQ咨询




