4、端口资源监控:用命令行工具看穿端口状态
端口监控这件事,说白了就是给系统做「心电图」。你想想看,端口就是服务的门牌号,门牌号挂了,服务自然就断了。我这些年排查过不少线上故障,十有八九都能在端口状态上找到线索。
这一章,咱们就聊聊怎么用 netstat、ss、lsof 这几个老牌工具,再加上 /proc 文件系统,把端口状态看得明明白白。
4.1 netstat:老牌工具,依然能打
netstat 我用了十几年,虽然现在有了更快的 ss,但很多老系统上它还是首选。它的核心能力就四个字:看连接状态。
4.1.1 常用参数组合
# 查看所有监听中的 TCP 端口
netstat -tlnp
# 查看所有连接(含已建立和监听)
netstat -antp
# 只看 UDP 端口
netstat -ulnp
# 显示进程 PID 和名称(-p 参数)
netstat -tlnp | grep 8080
我个人习惯,排查问题时先用 netstat -tlnp 看监听列表,确认服务有没有起来。再用 netstat -antp 看连接数,判断流量是否正常。
-t 只显示 TCP,-u 只显示 UDP,-l 只显示监听中的端口。组合起来用,输出干净很多。
4.1.2 连接状态解读
你看到 ESTABLISHED 别急着高兴,还得看数量。我在项目中遇到过,某台服务器 TIME_WAIT 状态飙到 3 万多,结果新连接全被堵死了。
| 状态 | 含义 | 常见原因 |
|---|---|---|
LISTEN |
端口正在监听 | 服务正常启动 |
ESTABLISHED |
连接已建立 | 正常通信中 |
TIME_WAIT |
主动关闭后等待 | 短连接过多,需优化 |
CLOSE_WAIT |
被动关闭,等待应用关闭 | 代码未正确关闭 socket |
SYN_SENT |
正在发起连接 | 目标端口不可达 |
CLOSE_WAIT 大量堆积,基本可以断定是应用层 bug。我曾经排查过一个 Java 服务,就是因为忘了在 finally 块里关连接,导致 CLOSE_WAIT 堆到 5000+,最终 OOM 挂掉。
4.2 ss:更快,更现代
说实话,现在新系统上我基本只用 ss。它直接从内核的 socket 哈希表读数据,比 netstat 遍历 /proc 快得多。尤其在高并发场景下,差距非常明显。
4.2.1 核心用法
# 查看所有 TCP 监听端口
ss -tlnp
# 查看所有连接(含状态统计)
ss -antp
# 只看某个端口的连接
ss -antp | grep :8080
# 按状态过滤
ss -antp state established
ss -antp state time-wait
# 显示 socket 使用详情(-m 参数)
ss -tlnpm
为什么 ss 更快?你想想看,netstat 每次都要读 /proc/net/tcp 然后解析文本,而 ss 直接调用内核的 netlink 接口,少了一层文本解析的开销。
netstat -antp 耗时约 3-5 秒,而 ss -antp 基本在 0.5 秒内出结果。线上排查时,这 2 秒可能就是生死之差。
4.2.2 统计信息
# 查看 socket 统计摘要
ss -s
# 输出示例
Total: 1234 (kernel 2345)
TCP: 567 (estab 456, closed 89, orphaned 12, synrecv 0, timewait 34/0), ports 89
重点关注 orphaned(孤儿连接)和 timewait 的数量。孤儿连接太多,说明应用层处理不过来,连接被内核强行断开了。
4.3 lsof:谁占了我的端口?
端口被占用了,但不知道是哪个进程?lsof 就是干这个的。它列出所有打开的文件,而 Linux 里「一切皆文件」,socket 也不例外。
4.3.1 查端口归属
# 查看 8080 端口被谁占用
lsof -i :8080
# 只看 TCP 端口
lsof -i tcp:8080
# 只看 UDP 端口
lsof -i udp:53
# 显示所有网络连接
lsof -i
# 结合 PID 查端口
lsof -p 12345 -i
输出里 COMMAND 是进程名,PID 是进程号,FD 是文件描述符。看到 FD 为 LISTEN 的就是监听中的端口。
lsof -i :8080 没输出,但端口确实被占了。后来才发现是权限问题——lsof 需要 root 权限才能看到所有进程的 socket。所以,排查时记得加 sudo。
4.3.2 查进程打开了哪些端口
# 查看 Nginx 进程打开了哪些端口
lsof -c nginx -i
# 查看某个用户的所有网络连接
lsof -u www-data -i
这个在安全审计时特别好用。比如你怀疑某个进程偷偷开了后门端口,用 lsof -p PID -i 一查,所有网络连接一目了然。
4.4 /proc 文件系统:底层视角
前面几个工具,说到底都是在读 /proc 里的数据。直接看 /proc,你能拿到最原始的信息,而且不受工具版本影响。
4.4.1 核心文件
| 文件路径 | 内容 | 用途 |
|---|---|---|
/proc/net/tcp |
TCP 连接表 | 查看所有 TCP 连接 |
/proc/net/udp |
UDP 连接表 | 查看所有 UDP 连接 |
/proc/net/tcp6 |
IPv6 TCP 连接表 | 查看 IPv6 连接 |
/proc/PID/fd/ |
进程的文件描述符 | 查看进程打开的 socket |
/proc/net/sockstat |
socket 统计 | 查看 socket 使用总量 |
4.4.2 手动解析 /proc/net/tcp
# 查看 TCP 连接表
cat /proc/net/tcp
# 输出格式(十六进制):
# sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt
# 0: 00000000:1F90 00000000:0000 0A 00000000:00000000 00:00000000 00000000
这里 local_address 是 IP:PORT 的十六进制表示。00000000:1F90 就是 0.0.0.0:8080。st 是状态码,0A 表示 LISTEN。
01= ESTABLISHED02= SYN_SENT03= SYN_RECV04= FIN_WAIT105= FIN_WAIT206= TIME_WAIT07= CLOSE08= CLOSE_WAIT09= LAST_ACK0A= LISTEN0B= CLOSING
4.4.3 通过 /proc/PID/fd 查 socket
# 查看 PID 为 12345 的进程打开了哪些 socket
ls -la /proc/12345/fd/ | grep socket
# 输出示例
lrwx------ 1 root root 64 Apr 10 10:00 3 -> socket:[123456]
lrwx------ 1 root root 64 Apr 10 10:00 4 -> socket:[123457]
方括号里的数字是 socket 的 inode 号。拿着这个号去 /proc/net/tcp 里搜,就能找到对应的连接信息。
/proc 虽然原始,但解析起来比较麻烦。我一般只在工具不可用或者需要批量采集数据时才用。比如写监控脚本时,cat /proc/net/tcp | wc -l 比调 ss 命令快得多。
4.5 知识体系总览
下面这张图,把端口监控的四个维度串起来了。你可以看到,netstat、ss、lsof 和 /proc 各有侧重,但底层数据源都是内核。
4.6 实战场景:快速定位端口冲突
最后,分享一个我常用的排查流程。假设你启动服务时提示「端口已被占用」:
- 第一步:确认端口状态
ss -tlnp | grep 8080或netstat -tlnp | grep 8080 - 第二步:找到占用进程
lsof -i :8080看 PID 和进程名 - 第三步:确认进程是否正常
ps -ef | grep PID看进程启动时间和参数 - 第四步:决定处理方式
如果是僵尸进程,kill -9 PID;如果是正常服务,考虑换端口
ss -tlnp 看监听列表,再用 ss -antp | wc -l 看总连接数。如果连接数异常,再用 ss -antp state time-wait | wc -l 看具体状态分布。三步下来,问题基本就定位了。
嗯,端口监控这块,工具不在多,会用就行。关键是理解每个工具的输出含义,以及它们背后的数据来源。下次遇到端口问题,别慌,按这个思路来,基本都能搞定。