最准的方法是直接读内核 socket 表,用 sudo ss -tuln——它直读内核网络子系统,实时无遗漏,LISTEN 状态即 bind()+listen() 的真实痕迹;-t 限 TCP,-u 限 UDP,-l 过滤监听态,-n 禁 DNS 解析,sudo 保障查系统服务权限。

最准的方法是直接读内核 socket 表,用 sudo ss -tuln ——其他工具要么慢、要么缺权限、要么只扫不监听,容易漏掉 root 进程开的 0.0.0.0:22 这类关键端口。
为什么 ss -tuln 是唯一能反映“真开放”的命令
ss 不走用户态解析,直读内核网络子系统,结果实时、无遗漏。它看到的 LISTEN 状态,就是进程调用了 bind() + listen() 的真实痕迹。
-
-t:只列 TCP 监听套接字(如 SSH、HTTP) -
-u:只列 UDP 监听套接字(如 DNS、NTP) -
-l:过滤出 LISTEN 状态(即“开了但还没连进来”的端口) -
-n:禁用反向 DNS 和服务名解析,避免卡顿或显示错乱(比如把:80解成:http)
不加 sudo 时,普通用户只能看到自己启动的进程;查 nginx、mysqld、sshd 这类系统服务,必须加 sudo。
lsof -i -P -n -s TCP:LISTEN 用来确认谁在占端口
当 ss 显示 0.0.0.0:3000,但你不确定是 node 还是 python 启的,lsof 能直接给出 PID、USER、COMMAND 字段。
-
-i:只显示网络相关文件(即 socket) -
-P:端口号不转服务名(绕过/etc/services) -
-n:IP 不反解(避免卡 DNS) -
-s TCP:LISTEN:精确过滤 TCP LISTEN 状态,排除已建立连接的干扰
注意:lsof 在最小化系统(如 Alpine 容器)里常未预装;若提示 command not found,别硬装,优先用 ss 查端口,再用 ps aux | grep 搜进程名。
别把防火墙放行端口和监听端口混为一谈
防火墙规则 ≠ 端口监听状态。一个端口完全可能:
- 进程在监听(
ss能看到),但防火墙没放行(外部连不上) - 防火墙放行了(
firewall-cmd --list-ports有输出),但根本没人监听(ss里找不到)
查防火墙本身:
- firewalld:
sudo firewall-cmd --list-ports - iptables:
sudo iptables -L -n -v | grep -i "accept" | grep -i "tcp\|udp" - ufw:
sudo ufw status verbose
这些命令只告诉你“流量能不能过”,不告诉你“有没有人在听”。真正判断“端口是否开放”,永远以 ss -tuln 输出为准。
nmap -Pn 127.0.0.1 容易误判,慎用
nmap 默认先发 ICMP ping 或 ARP 探测,而 Docker 容器、加固内核、某些云主机默认丢弃这些包,导致报 Host is down ——这不是端口问题,是 nmap 自己被环境拦住了。
- 必须加
-Pn:告诉nmap“别探测存活,直接扫” - 不加
sudo时,nmap实际退化为慢速connect()扫描(-sT),还可能被防火墙拦截 -
-sU(UDP 扫描)默认不启用,要单独加;全端口扫描(-p-)耗时长,日常不用
复杂点在于:监听地址决定对外可见性。0.0.0.0:80 可从任意网卡访问,127.0.0.1:3306 只能本机连——这个细节,ss 输出里就藏着,但很多人一眼扫过去就忽略了。


















