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 接口,少了一层文本解析的开销。

实战对比: 在 10 万连接数的服务器上,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 = ESTABLISHED
  • 02 = SYN_SENT
  • 03 = SYN_RECV
  • 04 = FIN_WAIT1
  • 05 = FIN_WAIT2
  • 06 = TIME_WAIT
  • 07 = CLOSE
  • 08 = CLOSE_WAIT
  • 09 = LAST_ACK
  • 0A = LISTEN
  • 0B = 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 各有侧重,但底层数据源都是内核。

端口资源监控知识体系 端口资源监控知识体系 监控目标:端口状态 + 连接数 + 进程归属 netstat ss lsof /proc 文件系统 查看监听端口 连接状态统计 高速查询 状态过滤 端口→进程映射 文件描述符查看 原始数据读取 批量采集 底层数据源:内核 Socket 哈希表

4.6 实战场景:快速定位端口冲突

最后,分享一个我常用的排查流程。假设你启动服务时提示「端口已被占用」:

  1. 第一步:确认端口状态
    ss -tlnp | grep 8080 或 netstat -tlnp | grep 8080
  2. 第二步:找到占用进程
    lsof -i :8080 看 PID 和进程名
  3. 第三步:确认进程是否正常
    ps -ef | grep PID 看进程启动时间和参数
  4. 第四步:决定处理方式
    如果是僵尸进程,kill -9 PID;如果是正常服务,考虑换端口
我的习惯: 排查端口问题时,我一般先跑 ss -tlnp 看监听列表,再用 ss -antp | wc -l 看总连接数。如果连接数异常,再用 ss -antp state time-wait | wc -l 看具体状态分布。三步下来,问题基本就定位了。

嗯,端口监控这块,工具不在多,会用就行。关键是理解每个工具的输出含义,以及它们背后的数据来源。下次遇到端口问题,别慌,按这个思路来,基本都能搞定。