3. Linux 系统排查:端口占用的五大法宝

端口被占了,服务起不来。这事儿我碰过太多次了。

刚入行那会儿,一遇到端口问题就慌。后来发现,Linux 下查端口就那么几个工具——netstat、ss、lsof、fuser,还有 /proc 文件系统。把它们用熟了,端口问题基本都能搞定。

这一章,我把这几个工具的用法和实战经验掰开揉碎了讲。你跟着走一遍,以后排查端口问题,心里就有底了。

核心思路:端口占用的本质是某个进程在监听或连接某个端口。我们的目标就是找到「哪个进程占用了哪个端口」,然后决定是杀掉它,还是换个端口。

Linux 端口排查工具全景图 端口占用排查 netstat ss lsof fuser /proc 文件系统 💡 实战建议 优先用 ss 替代 netstat(更快、更现代);lsof 适合查具体端口;fuser 适合快速杀进程;/proc 是终极手段

3.1 netstat 命令详解

netstat 是老牌工具了。我刚开始学 Linux 时,用的就是它。虽然现在 ss 更快,但很多老系统上还是得靠 netstat。

常用参数

参数 说明 我的用法
-t 显示 TCP 端口 查 TCP 服务必加
-u 显示 UDP 端口 DNS、NTP 这类用 UDP
-l 只显示监听中的端口 我最常用的组合
-n 以数字形式显示地址和端口 不加的话会去解析主机名,慢
-p 显示进程 PID 和名称 查谁占端口,靠它了
-a 显示所有连接 信息太多,一般配合 grep

我个人最常用的组合是:

# 查看所有监听中的 TCP 端口,显示进程信息
netstat -tlnp

# 查看某个端口是否被占用
netstat -tlnp | grep :8080

小技巧:netstat -tlnp 这个组合我几乎天天用。-t 只看 TCP,-l 只看监听,-n 不解析名字,-p 显示进程。四个参数一组合,干净利落。

输出解读

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 127.0.0.1:3306          0.0.0.0:*               LISTEN      5678/mysqld

看第二行:127.0.0.1:3306 表示 MySQL 只监听本地回环地址,外网访问不了。我曾经遇到过一个问题,数据库连不上,一查发现就是绑定了 127.0.0.1,改成 0.0.0.0 就好了。

注意:netstat 在较新的 Linux 发行版中可能默认没安装。如果提示命令找不到,用 yum install net-tools 或 apt install net-tools 装上就行。

3.2 ss 命令详解

ss 是 netstat 的现代替代品。说白了,它直接从内核获取 socket 信息,速度比 netstat 快得多。我现在的习惯是:能用 ss 就不用 netstat。

常用参数

参数 说明 等效 netstat
-t 显示 TCP socket -t
-u 显示 UDP socket -u
-l 只显示监听中的 socket -l
-n 不解析服务名 -n
-p 显示进程信息 -p
-s 显示统计信息 无直接等效

实战中我这样用:

# 查看所有监听中的 TCP 端口(推荐)
ss -tlnp

# 查看某个端口
ss -tlnp | grep :443

# 查看 socket 统计信息
ss -s

为什么推荐 ss? 在高并发服务器上,netstat 可能会卡住,而 ss 几乎瞬间出结果。我曾在一次生产事故中,靠 ss 快速定位了端口冲突,避免了服务中断。

输出解读

State      Recv-Q Send-Q  Local Address:Port    Peer Address:Port   Process
LISTEN     0      128     0.0.0.0:22            0.0.0.0:*           users:(("sshd",pid=1234,fd=3))
LISTEN     0      128     127.0.0.1:3306        0.0.0.0:*           users:(("mysqld",pid=5678,fd=16))

嗯,这里要注意:ss 的进程信息格式和 netstat 不太一样,但核心信息是一样的——PID、进程名、文件描述符。

3.3 lsof 命令详解

lsof 的全称是 List Open Files。Linux 下一切皆文件,socket 也是文件。所以 lsof 也能查端口。

我个人觉得 lsof 最方便的地方是:可以直接指定端口号,不用先列出来再 grep。

# 查看 8080 端口被谁占用
lsof -i :8080

# 查看所有网络连接
lsof -i

# 查看某个进程打开了哪些端口
lsof -i -p 1234

输出解读

COMMAND   PID   USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
java     12345 root   30u  IPv4   123456      0t0  TCP *:8080 (LISTEN)

看这一行:PID 是 12345,进程名是 java,监听在 8080 端口。我曾经用这个命令抓出过一个隐藏的 Java 进程,它占用了 8080 端口,但 ps aux 一时没找到——因为进程名被改了。

小技巧:lsof -i :端口号 是我排查端口问题时第一个敲的命令。简单直接,不用记那么多参数。

3.4 fuser 命令使用

fuser 这个工具,说实话,平时用得不多。但一旦需要「杀掉占用某个端口的进程」,它比前面几个都方便。

# 查看 80 端口被哪个进程占用
fuser 80/tcp

# 杀掉占用 80 端口的进程
fuser -k 80/tcp

# 查看详细信息(显示 PID)
fuser -v 80/tcp

小心使用:fuser -k 会直接杀掉进程。我曾经在生产环境上不小心用 fuser -k 8080/tcp 杀掉了 Tomcat,导致服务中断了 5 分钟。所以,用之前一定确认清楚。

输出示例

# fuser 80/tcp
80/tcp:               12345

# fuser -v 80/tcp
                     USER        PID ACCESS COMMAND
80/tcp:              root      12345 F....    nginx

3.5 /proc 文件系统查看

前面几个工具,说到底都是从 /proc 文件系统读取信息的。如果你在极端环境下——比如系统被精简到只有 cat 和 ls——那 /proc 就是你最后的武器。

查看进程的 socket 信息

# 查看 PID 为 1234 的进程打开了哪些文件描述符
ls -l /proc/1234/fd/

# 查看进程的网络连接信息
cat /proc/1234/net/tcp

/proc/net/tcp 解读

/proc/net/tcp 里的内容比较原始,但信息很全:

  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 12345 1 0000000000000000 100 0 0 10 0

这里 00000000:0016 表示 0.0.0.0:22(22 的十六进制是 16)。0A 表示 LISTEN 状态。

实战场景:有一次我登录一个 Docker 容器,里面连 netstat 和 ss 都没有。我直接用 cat /proc/net/tcp 查到了端口占用情况。这就是 /proc 的威力——它永远在那里。

状态码对照表

十六进制 TCP 状态
0A LISTEN
01 ESTABLISHED
02 SYN_SENT
03 SYN_RECV
04 FIN_WAIT1
05 FIN_WAIT2
06 TIME_WAIT

3.6 实战对比:什么时候用哪个?

场景 推荐工具 理由
快速查看监听端口 ss -tlnp 速度快,信息全
查某个具体端口 lsof -i :端口 直接指定,不用 grep
杀掉占用端口的进程 fuser -k 端口/tcp 一行搞定
老系统或最小化环境 netstat -tlnp 兼容性好
极端环境(无工具) /proc/net/tcp 终极手段

我的建议:把这五个工具都记在脑子里。平时用 ss 和 lsof 就够了,但关键时刻,多一个工具就多一条活路。