4. Linux 环境排查:ss、lsof、/proc 与 netstat
端口冲突和连接问题,十有八九是在 Linux 服务器上遇到的。Windows 上出问题,重启大法好;Linux 上出问题,你得跟内核打交道。
我个人习惯,排查这类问题从来不用图形工具。命令行,一把梭。今天聊的这四个工具——ss、lsof、/proc 文件系统、netstat -tulpn——是我日常排查的「四件套」。它们各有侧重,但组合起来,几乎没有查不清的连接问题。
核心思路:先看端口有没有被占用,再看进程是谁,最后看内核状态。顺序别搞反。
4.1 ss:现代 Linux 的 socket 瑞士军刀
先聊 ss。为什么把它放第一个?因为它快。比 netstat 快一个数量级。
我记得以前排查一个高并发 Web 服务器,netstat 跑一次要等好几秒,ss 几乎瞬间出结果。你想想看,线上故障的时候,每一秒都很宝贵。
ss 直接从内核的 socket 哈希表读取数据,不依赖 /proc 的解析。这是它快的根本原因。
我的常用命令:
ss -tuln:只看 TCP/UDP 监听端口,不解析服务名ss -tulnp:加上-p显示进程信息ss -tan state established:只看已建立的 TCP 连接ss -s:socket 统计摘要,一眼看出问题
举个例子,查 8080 端口谁在用:
ss -tulnp | grep 8080
输出类似:
LISTEN 0 100 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=12345,fd=23))
看到 LISTEN 状态,说明端口已被占用。PID 12345,Java 进程。接下来就知道该找谁了。
注意:ss -p 需要 root 权限才能看到所有进程信息。普通用户只能看到自己的进程。
4.2 lsof:谁动了我的端口?
lsof 全称是 List Open Files。Linux 里一切皆文件,socket 也是文件。所以 lsof 能告诉你哪个进程打开了哪个端口。
我个人觉得 lsof 最爽的地方是,它不仅能查端口,还能查文件、目录、设备。但今天我们只聊端口排查。
查端口占用,我习惯用:
lsof -i :8080
输出:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 12345 root 23u IPv4 123456 0t0 TCP *:8080 (LISTEN)
信息比 ss 更丰富。能看到用户、文件描述符、节点号。有一次我排查一个诡异问题,端口显示被占用但进程查不到,用 lsof 发现是某个僵尸进程残留的 socket 文件描述符。
避坑指南:我曾经遇到一个情况,ss 和 netstat 都查不到端口占用,但服务就是起不来。最后用 lsof -i :端口号 才发现,是某个 Docker 容器的端口映射占用了宿主机端口。容器内的进程在宿主机上看不到,但 lsof 能穿透。
4.3 /proc 文件系统:内核的「后门」
/proc 是 Linux 内核暴露给用户态的一个虚拟文件系统。说白了,就是内核把内部状态以文件形式展示给你看。
我刚开始学 Linux 时,觉得 /proc 很神秘。后来发现,ss、lsof、netstat 这些工具,底层都在读 /proc。你直接读它,能看到更原始的信息。
几个常用的路径:
| 路径 | 内容 | 用途 |
|---|---|---|
/proc/net/tcp |
TCP socket 表 | 查看所有 TCP 连接 |
/proc/net/udp |
UDP socket 表 | 查看所有 UDP 连接 |
/proc/[pid]/fd/ |
进程打开的文件描述符 | 查看进程持有的 socket |
/proc/[pid]/net/tcp |
进程视角的网络命名空间 | 容器内网络排查 |
举个例子,直接看 TCP 连接表:
cat /proc/net/tcp | head -10
输出是十六进制格式的,不太友好。但有时候工具查不到,直接读 /proc 反而能发现线索。我记得有一次排查内核 bug,ss 和 netstat 都卡住了,但 /proc/net/tcp 还能读,帮我定位到了问题。
小技巧:用 ls -l /proc/[pid]/fd/ | grep socket 可以快速列出进程打开的所有 socket 文件描述符。配合 lsof 使用,效果更佳。
4.4 netstat -tulpn:老将出马
虽然 ss 是更现代的替代品,但 netstat 依然在很多老系统上服役。而且,有些运维老手就认 netstat。
netstat -tulpn 这个组合参数,我闭着眼睛都能打出来:
-t:TCP-u:UDP-l:只显示监听中的 socket-p:显示进程 PID 和名称-n:不解析服务名,直接显示 IP 和端口
完整命令:
netstat -tulpn
输出示例:
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1234/sshd
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 12345/java
tcp6 0 0 :::80 :::* LISTEN 5678/nginx
一眼就能看到哪些端口在监听。Recv-Q 和 Send-Q 列也很重要——如果 Recv-Q 一直不为零,说明有数据堆积,可能是应用处理不过来。
注意:很多新系统默认不装 net-tools 包(netstat 所属的包)。如果你在容器或最小化安装的系统上跑 netstat 报错,别慌,装一下或者直接用 ss。
4.5 实战:组合拳排查端口冲突
光讲工具没意思,咱们来一个真实场景。
场景:部署一个 Java 应用,端口 8080,启动报错「Address already in use」。
排查步骤:
- 第一步:确认端口占用
或者ss -tulnp | grep 8080lsof -i :8080 - 第二步:确认进程信息
假设看到 PID 是 12345,进程名是 java。但不确定是不是同一个应用?
或者直接看ps -ef | grep 12345/proc:cat /proc/12345/cmdline - 第三步:判断是否可杀
如果是你自己的进程,直接 kill。如果是别人的,先沟通。
kill -9 12345 - 第四步:确认端口已释放
ss -tulnp | grep 8080没有输出,说明端口已释放。
- 第五步:重启应用
嗯,看起来很简单对吧?但实际中经常遇到「杀不死」的情况。比如进程是 root 启动的,你用的是普通用户;或者进程处于 D 状态(不可中断睡眠)。这时候 /proc 就派上用场了——直接看 /proc/[pid]/status 里的进程状态。
经验之谈:我曾经遇到一个极端情况,端口被占用但查不到 PID。用 ss -tulnp 显示 - 而不是 PID。最后用 fuser 8080/tcp 才找到。嗯,fuser 也是个好工具,但今天不展开。
4.6 工具对比:什么时候用哪个?
| 场景 | 推荐工具 | 原因 |
|---|---|---|
| 快速查端口占用 | ss -tulnp |
速度最快,信息完整 |
| 查进程打开的所有端口 | lsof -i |
能列出进程所有网络连接 |
| 内核级调试 | /proc/net/tcp |
绕过工具,直接看原始数据 |
| 老系统兼容 | netstat -tulpn |
老系统上 ss 可能没有 |
| 容器内排查 | /proc/[pid]/net/tcp |
容器网络命名空间隔离 |
你想想看,这四个工具就像四把不同的螺丝刀。没有哪一把是万能的,但组合起来,几乎没有拧不开的螺丝。
最后说一句:别死记命令。理解它们背后的原理——socket 在内核里的表示、进程与文件描述符的关系、/proc 的虚拟文件系统机制——比背一百个参数都管用。