这个命令是干啥的
tcpdump 是 Linux 上最经典的网络抓包工具,没有之一。它能监听网卡上流经的所有网络数据包,然后把包的内容打印出来或者保存成 pcap 文件。说白了,就是把你服务器网线里的数据"偷听"下来给你看。
我第一次用 tcpdump 是在排查一个线上问题:某台服务器的 Nginx 时不时返回 502,但看日志啥异常都没有。老同事过来敲了一行 tcpdump -i eth0 port 80 -n,观察了几秒钟就说"上游服务超时了"。我当时就觉得这工具太强了。
相比于 Wireshark 的图形界面,tcpdump 是纯命令行的,在没 GUI 的服务器上就是神器。配合 Wireshark 做后续分析,基本能解决 90% 的网络问题。
基本用法(3分钟上手)
抓取所有流量(别在生产环境干这个)
# 监控 eth0 网卡的所有流量,不解析 DNS 名称
tcpdump -i eth0 -n
-i 指定网卡,-n 不把 IP 解析成域名。不加 -n 的话,tcpdump 会频繁做 DNS 查询,又慢又容易混淆。我每次都加 -nn,连端口也不解析成服务名,更清爽。
按端口抓取
# 只抓 80 端口的流量(HTTP)
tcpdump -i eth0 port 80 -nn
# 抓多个端口
tcpdump -i eth0 port 80 or port 443 -nn
这是最常用的方式,指定端口能过滤掉大部分噪音。
按主机抓取
# 只抓和特定 IP 通信的包
tcpdump -i eth0 host 192.168.1.100 -nn
# 只抓从某 IP 发出来的包
tcpdump -i eth0 src host 192.168.1.100 -nn
# 只抓发给某 IP 的包
tcpdump -i eth0 dst host 192.168.1.100 -nn
控制抓包数量
# 抓 10 个包就自动停止
tcpdump -i eth0 -c 10 -nn
-c 参数特别实用,抓够数量就停,不用手动 Ctrl+C。
保存抓包结果
# 把抓到的内容保存成 pcap 文件,方便后续分析
tcpdump -i eth0 -w capture.pcap port 80
# 读取保存的 pcap 文件
tcpdump -r capture.pcap -nn
保存成 pcap 文件后,可以下载到本地用 Wireshark 打开分析,图形界面看请求更直观。
进阶骚操作
组合过滤表达式
tcpdump 的过滤语法基于 BPF(Berkeley Packet Filter),表达能力很强:
# 抓从 192.168.1.100 发往 80 端口,且不是 SSH 的包
tcpdump -i eth0 src host 192.168.1.100 and dst port 80 and not port 22 -nn
逻辑运算符:and、or、not,自由组合。
# 抓特定的 TCP 标志位,比如 SYN 包
tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn) != 0' -nn
# 抓 RST 包(连接被重置)
tcpdump -i eth0 'tcp[tcpflags] & (tcp-rst) != 0' -nn
SYN 包可以用来看连接请求,RST 包经常代表连接被拒绝或者异常断开,排查问题的时候很有用。
查看 HTTP 请求内容
# 抓 HTTP GET 请求,显示完整内容
tcpdump -i eth0 port 80 -X -nn
# 更优雅的方式,用 -A 只看 ASCII 内容
tcpdump -i eth0 port 80 -A -nn
-X 同时显示 hex 和 ASCII,-A 只显示 ASCII。对于我们这种人类,看 ASCII 就够用了。
如果你只想看 HTTP 请求行和状态行:
# 用 -s 限制抓包长度,只看 TCP 头部和应用层前 200 字节
tcpdump -i eth0 port 80 -s 200 -A -nn
显示时间戳
# 抓包时显示精确到微秒的时间戳
tcpdump -i eth0 port 80 -tttt -nn
-tttt 能显示到微秒级别的时间,排查时序问题特别好用。比如你想看某个请求的响应时间、或者两个请求的先后顺序,这个参数能帮上大忙。
抓取完整包内容
# 默认只抓 96 字节,用 -s 0 抓完整包
tcpdump -i eth0 port 80 -s 0 -w full_capture.pcap
默认每个包只抓 96 字节,对于看协议头够了。但如果要分析应用层数据(比如 HTTP body),得用 -s 0 抓完整包。注意抓完整包会大很多,磁盘空间要留够。
避坑指南
1. 大流量抓包丢包问题
这是最坑的地方。线上服务器流量一大,tcpdump 默认的抓包缓冲区不够,就会丢包。你看到抓到的包少了,但以为自己抓全了,这就出大问题了。
# 设置更大的抓包缓冲区(单位 KB,默认约 2MB)
tcpdump -i eth0 -B 4096 -w capture.pcap
# 抓包结束后看丢包率
tcpdump -r capture.pcap -nn 2>&1 | tail -3
-B 参数设置缓冲区大小,一般设到 4096(4MB)或者 8192(8MB)。抓完包之后用 tcpdump -r 读包时,如果有 packets captured 和 packets received by filter 数字不一致,后面的差值就是丢包数。
2. 权限问题
普通用户不能抓包,必须 root 或者有 CAP_NET_RAW 和 CAP_NET_ADMIN 权限:
# 报错: tcpdump: eth0: You don't have permission to capture on that device
sudo tcpdump -i eth0
或者给特定用户授权:
# 给当前用户添加抓包权限(Debian/Ubuntu)
sudo setcap cap_net_raw,cap_net_admin+eip /usr/sbin/tcpdump
3. 抓包影响性能
抓包本身会消耗 CPU 和内存。线上大流量服务器,抓包可能导致 CPU 飙升。建议这么做:
- 用精确的过滤条件,别抓全量
- 使用 -c 限制数量
- 抓包文件不要写虚拟磁盘(如网络存储),写本地磁盘
4. 不要抓 SSH 端口
# 你如果 SSH 连服务器,千万别抓 port 22,自己把自己抓进去
tcpdump -i eth0 port 22 # 你的 SSH 连接会被自己的抓包拖慢甚至断掉
我犯过这个错:在远程服务器上抓自己的 SSH 端口,结果 SSH 响应越来越慢,最后直接断开,我只能找机房的人去重启。
实战场景
场景一:排查 Nginx 502 Bad Gateway
Nginx 报 502,一般是后端服务挂了或者超时了。用 tcpdump 看一眼就清楚了:
# 抓 Nginx 和后端服务(假设后端在 127.0.0.1:8080)的通信
tcpdump -i lo port 8080 -A -tttt -nn
看输出:
- 如果只看到 SYN 没看到 SYN-ACK:后端根本没回应,服务没起或者端口不对
- 如果看到 SYN 发了但 RST 回来:后端拒绝了连接
- 如果看到请求发出去了但很久没响应:后端处理慢,超时了
场景二:看 DNS 解析有没有问题
# 抓 DNS 请求和响应(DNS 用 UDP 53 端口)
tcpdump -i eth0 port 53 -nn -tttt
看响应里的 IP 对不对。如果请求发出去没有响应,那就是 DNS 服务器有问题或者防火墙拦了。
场景三:配合 Wireshark 做深入分析
# 服务器上抓包保存
tcpdump -i eth0 host 10.0.0.5 -s 0 -w problem.pcap -C 100
-C 100 表示每个文件最大 100MB,自动切割。然后 scp 到本地用 Wireshark 打开。
Wireshark 的牛逼功能包括:看 TCP 流重组、分析 HTTP 请求响应、看 TCP 重传率、画时序图。我强烈推荐花半个小时学一下 Wireshark 的基本操作,和 tcpdump 简直是绝配。
场景四:查慢请求
# 抓 80 端口,只看 SYN 包,统计连接建立时间
tcpdump -i eth0 'tcp port 80 and tcp[tcpflags] & (tcp-syn) != 0' -tttt -nn
观察 SYN 和 SYN-ACK 的时间差,如果超过几百毫秒,说明网络延迟大或者对端负载高。
今日作业
你们公司的应用服务器突然出现大量 502 错误。请用 tcpdump 排查问题,要求:
1. 只抓连接请求(SYN 包),排除无关流量
2. 限制只抓 100 个包,避免产生大文件
3. 显示精确时间戳,记录每个包的时间
4. 保存结果到 pcap 文件,供后续分析
试着写一条完整的 tcpdump 命令,并解释你怎么从抓包结果判断是"后端服务挂了"还是"后端响应太慢"。