2. 常见排错工具:netstat、ss、lsof、tcpdump、strace 的使用方法与实战技巧
端口复用出了问题,你第一反应是什么?
我个人的习惯是——先别急着翻代码,先看看系统到底在干什么。说白了,排错就像破案,你得先有线索。而 netstat、ss、lsof、tcpdump、strace 这五个工具,就是我最常用的「现场勘查工具」。
这一章,我把它们的使用方法和实战技巧掰开揉碎讲清楚。每个工具我都会结合真实场景,告诉你什么时候用它、怎么用、以及常见的坑在哪。
核心思路:排错不是靠猜,是靠证据。这五个工具分别从「连接状态」「进程绑定」「网络流量」「系统调用」四个维度给你证据。你掌握得越熟练,定位问题的速度就越快。
2.1 netstat —— 老牌工具,但别滥用
netstat 是我刚入行时用的第一个网络排错工具。说实话,现在生产环境我很少用它了,因为 ss 更快。但有些老系统上只有 netstat,你还是得会用。
常用场景:查看某个端口是否在监听、统计当前连接数。
# 查看所有监听端口
netstat -tlnp
# 查看所有连接(包括已建立的)
netstat -anp | grep 8080
# 统计各状态连接数
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
我的经验:netstat 的 -tlnp 组合是我最常用的。t 表示 TCP,l 表示 listening,n 用数字显示地址,p 显示进程信息。少一个参数,输出就可能让你看花眼。
注意:netstat 在连接数多的机器上会非常慢。我曾经在一台有 10 万连接的网关设备上跑 netstat,结果卡了将近 30 秒才出结果。这种场景下,请用 ss。
2.2 ss —— 现代替代品,性能碾压
ss 是 iproute2 包里的工具,说白了就是 netstat 的升级版。它直接从内核的 socket 信息中读取数据,而不是解析 /proc 文件系统,所以 速度比 netstat 快一个数量级。
我个人习惯:只要系统支持,我就用 ss 代替 netstat。
# 查看所有 TCP 监听端口
ss -tlnp
# 查看所有 UDP 监听端口
ss -ulnp
# 查看指定端口(比如 8080)
ss -tlnp | grep 8080
# 查看所有已建立的连接
ss -tunp state established
# 按状态过滤(比如 TIME-WAIT)
ss -tunp state time-wait
| 对比项 | netstat | ss |
|---|---|---|
| 数据来源 | /proc/net/tcp 等 | 内核 netlink 接口 |
| 性能 | 连接数多时慢 | 快,适合高并发 |
| 状态过滤 | 需配合 grep/awk | 原生支持 state 过滤 |
| 推荐场景 | 老系统、临时查看 | 生产环境首选 |
实战技巧:用 ss 排查端口复用冲突时,我经常这样用:ss -tlnp sport = :8080。这个语法可以直接过滤源端口,比 grep 精准得多。
2.3 lsof —— 谁动了我的端口?
lsof 的全称是 List Open Files。在 Linux 里,一切皆文件,socket 也是文件。所以 lsof 能告诉你:哪个进程打开了哪个端口。
我记得有一次线上告警,说 3306 端口被占用了。用 netstat 一看,确实有进程在监听,但进程名显示不出来(权限问题)。这时候 lsof 就派上用场了。
# 查看哪个进程占用了 3306 端口
lsof -i :3306
# 查看某个进程打开了哪些端口
lsof -i -p 12345
# 查看所有 TCP 监听
lsof -iTCP -sTCP:LISTEN
# 查看某个用户的所有网络连接
lsof -i -u nginx
避坑指南:lsof 默认会解析主机名,如果 DNS 有问题,它会卡住。加上 -n 参数(不解析主机名)可以避免这个问题。我习惯用 lsof -nP -i :端口,P 表示不解析端口名。
2.4 tcpdump —— 网络排错的终极武器
tcpdump 是抓包工具。当 netstat 和 ss 告诉你「有连接」,但应用层就是不通时,就该 tcpdump 上场了。
说白了,tcpdump 能让你看到 网络上实际发生了什么,而不是进程以为发生了什么。
# 抓取 8080 端口的流量
tcpdump -i any port 8080
# 抓取指定主机的流量
tcpdump -i eth0 host 192.168.1.100
# 抓取并保存到文件(方便后续分析)
tcpdump -i any -w capture.pcap port 8080
# 读取抓包文件
tcpdump -r capture.pcap
# 抓取 TCP 三次握手包
tcpdump -i any 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0'
注意:tcpdump 需要 root 权限。另外,在生产环境抓包时,尽量用 -c 数量 限制抓包数量,或者用 -s 0 抓完整包(默认只抓前 68 字节)。我曾经见过有人没加限制,直接把磁盘抓满了……
实战场景:端口复用导致连接被错误路由时,tcpdump 能帮你看到 SYN 包发到了哪个进程。比如你期望连接打到 Nginx,结果 tcpdump 显示 SYN 被另一个进程的 socket 接收了——这就是典型的端口复用冲突。
2.5 strace —— 深入内核的最后一步
strace 追踪进程的系统调用。当上面四个工具都查不出问题时,我会用 strace 看看进程到底在干什么。
嗯,这里要注意:strace 对性能有影响,生产环境慎用。
# 追踪某个进程的系统调用
strace -p 12345
# 只追踪网络相关的系统调用
strace -p 12345 -e trace=network
# 追踪 bind、listen、accept 等调用
strace -p 12345 -e trace=bind,listen,accept
# 输出到文件
strace -p 12345 -o /tmp/strace.log
# 追踪新启动的进程
strace -f -o /tmp/strace.log ./myapp
| 系统调用 | 含义 | 排错场景 |
|---|---|---|
| bind() | 绑定端口 | 端口被占用时返回 EADDRINUSE |
| listen() | 开始监听 | 确认进程是否真的在监听 |
| accept() | 接受连接 | 确认连接是否被接收 |
| setsockopt() | 设置 socket 选项 | 检查 SO_REUSEADDR 是否设置 |
我的经验:有一次排查端口复用问题,用 netstat 和 lsof 都显示进程在监听,但就是连不上。最后用 strace 一看,发现进程调了 bind() 之后根本没调 listen()——代码写漏了。这种问题,只有 strace 能抓到。
2.6 五工具协同排错实战流程
光知道单个工具怎么用还不够,你得知道 什么时候用哪个。下面是我总结的排错流程:
- 第一步:ss 快速扫描 —— 查看目标端口是否在监听,状态是否正常。
- 第二步:lsof 确认进程 —— 如果端口在监听,确认是哪个进程。
- 第三步:tcpdump 抓包 —— 如果连接异常,抓包看网络层面发生了什么。
- 第四步:strace 深挖 —— 如果网络层面正常,但应用层异常,追踪系统调用。
- 第五步:交叉验证 —— 用多个工具的结果互相印证,避免单一工具误导。
核心原则:从外到内,从快到慢。先用轻量工具缩小范围,再用重量工具精确定位。别一上来就 strace,那就像用大炮打蚊子。