4. Linux 环境排查:ss、lsof、/proc 与 netstat

端口冲突和连接问题,十有八九是在 Linux 服务器上遇到的。Windows 上出问题,重启大法好;Linux 上出问题,你得跟内核打交道。

我个人习惯,排查这类问题从来不用图形工具。命令行,一把梭。今天聊的这四个工具——ss、lsof、/proc 文件系统、netstat -tulpn——是我日常排查的「四件套」。它们各有侧重,但组合起来,几乎没有查不清的连接问题。

核心思路:先看端口有没有被占用,再看进程是谁,最后看内核状态。顺序别搞反。

Linux 端口与连接排查四件套 排查目标 ss lsof /proc netstat 快速查 socket 状态 查进程打开的文件 内核级信息查看 传统网络统计 组合使用,覆盖 95% 的排查场景

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」。

排查步骤:

  1. 第一步:确认端口占用
    ss -tulnp | grep 8080
    或者
    lsof -i :8080
  2. 第二步:确认进程信息

    假设看到 PID 是 12345,进程名是 java。但不确定是不是同一个应用?

    ps -ef | grep 12345
    或者直接看 /proc:
    cat /proc/12345/cmdline
  3. 第三步:判断是否可杀

    如果是你自己的进程,直接 kill。如果是别人的,先沟通。

    kill -9 12345
  4. 第四步:确认端口已释放
    ss -tulnp | grep 8080

    没有输出,说明端口已释放。

  5. 第五步:重启应用

嗯,看起来很简单对吧?但实际中经常遇到「杀不死」的情况。比如进程是 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 的虚拟文件系统机制——比背一百个参数都管用。