1. 端口排查才是Linux运维的分水岭
我一直觉得,Linux命令学到最后,拼的不是背了多少条命令,而是遇到问题时的排查思路。特别是端口相关的问题——服务起不来、外部访问不通、端口被占、防火墙挡了——这些场景几乎每周都会遇到。这篇是系列第十三篇,我就专门把端口管理和网络排查这条线串起来讲透。
先说个我自己的真实经历。有一回线上环境的一个Java服务突然连不上了,开发那边一口咬定“服务端口明明监听着”,我上去一看,ss -lntp 确实显示 8080 端口在 LISTEN 状态,但外部怎么都连不上。折腾了半天才发现,问题是防火墙规则在服务启动后被某人手动改过,新加的规则没有生效,DROP 策略把外部流量全挡了。那一次之后我就意识到,端口管理不只是会看几个命令,而是一整套“监听确认 → 进程定位 → 防火墙核对 → 连通性验证”的排查链路。
这篇文章适合谁看?刚接触 Linux 的运维新人、自己搭服务的老开发、还有面试前临时抱佛脚的朋友,都能从中拿到能直接落地的操作。我会把端口相关的高频命令、它们背后的原理、以及真实场景中的排查思路全部串起来,尽量让读完的人能直接“抄作业”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先用对工具:ss、netstat、lsof 到底该用哪个
很多人一上来就问“查看端口用什么命令”,网上答案五花八门。其实核心就三个:ss、netstat、lsof。但它们的定位和使用场景差别挺大,选错工具会让排查效率大打折扣。
2.1 为什么我强烈推荐直接用 ss
如果你还在用 netstat 查端口,说实话该换换了。netstat 来自 net-tools 这个老工具包,作者早就不维护了,很多新版 Linux 发行版默认都没装。而 ss 是 iproute2 工具包里的,替代 netstat 地位,几乎所有现代系统都自带。
更重要的是,ss 读取的是内核中 /proc/net 目录下的 socket 信息,内核直接提供的数据,性能比 netstat 好很多。在连接数上万的服务器上,netstat 跑一次可能要卡几秒,ss 基本是秒出结果。我实测过一个场景:一台跑着 Nginx 的机器上有几万个 TIME_WAIT 连接,netstat -an | grep 8080 跑了将近十秒,ss -lnt 瞬间出结果。
常用姿势:
bash复制# 查看所有监听的 TCP 端口
ss -lnt
# 查看所有监听端口,带进程信息(需要 root 权限)
ss -lntp
# 查看所有 TCP 连接(包含 ESTABLISHED、TIME_WAIT 等状态)
ss -ant
# 查看所有 UDP 监听端口
ss -lun
参数解释一下:-l 表示 listening(只显示监听中的连接),-n 表示不解析服务名直接显示数字端口,-t 表示 TCP 协议,-p 显示进程信息,-u 表示 UDP。这组参数要记熟,排查端口第一步基本都是它。
2.2 lsof 的不可替代场景
lsof 的定位不太一样,它更适合做“反向查询”——我已知端口,想知道是哪个进程占用的;或者我被某文件占用问题卡住,想查谁在用这个文件。虽然 ss -lntp 也能看到进程 PID,但 lsof 提供的信息更完整,比如用户、进程名、FD(文件描述符)类型。
bash复制# 查看某个端口被哪个进程占用
lsof -i:8080
# 只看 TCP 端口的占用情况
lsof -iTCP -sTCP:LISTEN
# 查看某个进程打开了哪些端口
lsof -p 12345
我实际用 lsof 最多的时候是排查“Address already in use”。报错只告诉你端口被占了,但不说是谁占的。这时候 lsof -i:端口号 一条命令,进程 PID、用户、启动命令全出来了。
需要注意的是,lsof 在没有 root 权限时只能看到自己进程的信息,排查别人启动的服务端口时,要么加 sudo,要么让管理员帮你跑。
2.3 老牌命令 netstat 仍然有用的两个场景
虽然不推荐主力使用,但 netstat 有两个场景至今没法完全替代。
第一个是查看路由表:netstat -rn,虽然 ip route 也能看,但很多老运维习惯看 netstat 的格式,输出更直观。
第二个是统计协议栈信息:netstat -s 会输出 TCP/UDP/ICMP 的各种统计计数,包括连接重置、超时、丢包等。排查网络质量问题时,这个命令提供的数据比 ss 更全面。比如 TCP 重传率异常升高,netstat -s | grep -i retrans 就能看到具体数字。
2.4 一个端口占用排查命令速查表
| 场景 | 推荐命令 | 说明 |
|---|---|---|
| 查看本机所有监听端口 | ss -lntp |
最推荐,速度快 |
| 查看某个端口是否被占用 | ss -lnt | grep 8080 |
确认端口状态 |
| 查看谁占用了 8080 端口 | lsof -i:8080 |
显示进程详情 |
| 查看某个进程的端口 | ss -lntp | grep 12345 |
按 PID 过滤 |
| 查看所有 TCP 连接状态 | ss -ant |
含 ESTABLISHED 等 |
| 查看网卡和路由表 | netstat -rn |
老命令但好用 |
| 查看网络协议统计 | netstat -s |
排查丢包重传 |
这份表基本覆盖了日常 90% 的端口查询需求,先记住 ss -lntp 和 lsof -i:端口,其他用到再查。
3. 从定位到关闭:一次完整的端口占用排查实操
光会看命令不行,得串联成完整的操作流程。我用一个具体场景来走一遍:假设你的服务在 9090 端口起不来,报错提示端口被占用。
3.1 第一步:确认端口确实被占用
bash复制ss -lnt | grep 9090
如果输出类似这样:
code复制LISTEN 0 128 0.0.0.0:9090 0.0.0.0:*
说明端口确实被某个进程监听了。注意看 0.0.0.0:9090 这个信息,它表示监听在所有网卡的 9090 端口上。如果显示的是 127.0.0.1:9090,那说明只监听了回环地址,外部访问是进不来的。
3.2 第二步:找到占用端口的进程
bash复制lsof -i:9090
或者:
bash复制ss -lntp | grep 9090
ss 需要 root 权限才能显示进程名,所以建议直接 sudo ss -lntp | grep 9090。输出中会带 users:(("java",pid=12345,fd=128)) 这样的信息,告诉你 PID 和进程名。
到这一步,我可以选择核实一下这个进程是不是正常的业务进程。用 ps -fp 12345 查看进程的启动时间、启动命令,再判断能不能安全处理。如果是僵尸进程或者误启动的旧实例,直接处理没问题;如果是正常业务进程,就得换个端口或者协调业务方。
3.3 第三步:处理方式的选择与执行
处理占用端口的进程通常有三种方式,按优先级排列:
bash复制# 方式一:优雅停止(支持 PID)
kill 12345(先尝试 SIGTERM,给进程清理资源的机会)
# 方式二:强制终止
kill -9 12345(进程无响应时才用)
# 方式三:修改服务配置换端口
我在实际踩坑中得出的经验是:kill -9 要慎用。它会直接终止进程而不给它清理资源的机会,可能留下临时文件、未落盘的数据,甚至导致数据库数据不一致。如果是 Java 服务,kill -9 还会导致 JVM 不执行关闭钩子,一些注册到注册中心的信息无法注销,造成“幽灵实例”问题。
先 kill,等十秒钟看进程还在不在,实在不行再 kill -9。
3.4 第四步:确认端口已经释放
bash复制ss -lnt | grep 9090
没有输出,说明端口释放了。这时候再启动你自己的服务即可。
3.5 深入 /proc 文件系统查看 TCP 状态细节
如果你连 ss 和 lsof 都没装(比如在极简容器环境里),还有一个“底牌”——直接看内核的 /proc/net/tcp 文件:
bash复制cat /proc/net/tcp | grep ":3842"
注意这里端口号是十六进制格式,9090 的十六进制是 0x2382。文件里的每一行代表一条 TCP 连接,sl 是连接序号,local_address 和 rem_address 分别是本地和远端地址(IP:端口),st 是连接状态码。状态码对应关系:0A 是 LISTEN,01 是 ESTABLISHED,06 是 TIME_WAIT。
说实话日常排查基本用不上这个,但理解它的存在能帮你建立“一切皆文件”的 Linux 思维。ss 和 netstat 本质上都是读 /proc/net 的数据再格式化展示,底层逻辑是一样的。
4. 防火墙规则:端口放行与排障的实操作业
端口查清楚了,服务也起来了,但外部还是访问不通——这种时候八成是防火墙挡了。这是我从 “9090 端口什么再用”这个热门搜索词上看到的高频问题背后的真实需求。下面讲清楚 Linux 下两大防火墙体系的操作方法。
4.1 firewalld 体系:CentOS 7+ 和 RHEL 系标配
firewalld 的核心理念是 zone(区域),不同网络接口可以归属不同 zone,每个 zone 设置不同的放行策略。默认的 public zone 表示信任度较低的公共网络,一般外部流量都走这里。
bash复制# 查看 firewalld 运行状态
systemctl status firewalld
# 查看当前默认区域
firewall-cmd --get-default-zone
# 查看当前所有放行的端口
firewall-cmd --list-ports
# 临时放行(重启或 reload 后失效)
firewall-cmd --add-port=8080/tcp
# 永久放行
firewall-cmd --permanent --add-port=8080/tcp
# 移除端口
firewall-cmd --permanent --remove-port=8080/tcp
# 永久改动后必须 reload
firewall-cmd --reload
有个细节非常容易忽略:--permanent 参数加上之后,规则是写入了永久配置,但不会立即生效,必须执行 firewall-cmd --reload。而直接不加 --permanent 的放行,是立即生效的,但重启后丢失。很多人的误区是加了 permanent 就觉得万事大吉,也不 reload,然后发现端口还是不通。
放行端口区间也是常用操作,比如放行 8000 到 8100 的所有 TCP 端口:
bash复制firewall-cmd --permanent --add-port=8000-8100/tcp
firewall-cmd --reload
4.2 iptables 体系:规则链的底层逻辑
虽然 firewalld 是更上层的工具,但它是通过调用 iptables 来实现的。理解了 iptables 的规则链,排障时才能从根上找到问题。
iptables 的流程可以简化理解为:数据包进入本机后,按顺序匹配 INPUT 链的规则。每条规则有 target(目标动作),常见的有 ACCEPT(接受)、DROP(丢弃)、REJECT(拒绝)。DROP 和 REJECT 的区别是:DROP 直接把包扔掉不给任何回应,客户端会一直等到超时;REJECT 会给客户端回一个拒绝的响应,比如 “Connection refused”,客户端立刻知道连不上。
端口排障中最常用的几条:
bash复制# 查看所有规则(带行号)
iptables -L -n --line-numbers
# 查看 INPUT 链规则
iptables -L INPUT -n --line-numbers
# 在指定行号插入放行规则
iptables -I INPUT 5 -p tcp --dport 8080 -j ACCEPT
# 追加放行规则
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
# 删除某条规则
iptables -D INPUT 5
我强烈建议插入规则用 -I 指定行号,因为规则是顺序匹配的,如果前面已经有一条 DROP all 的规则,你追加在末尾的 ACCEPT 根本没机会执行。这在排查“明明加了放行规则还是不通”的案例中非常常见。
4.3 nftables:新一代防火墙框架
如果你的系统是较新的发行版,比如 CentOS 8+ 或 Debian 11+,底层可能已经换成了 nftables。nft 命令的语法和 iptables 不太一样,但思路相通:
bash复制# 查看规则表
nft list ruleset
# 添加放行规则(TCP 8080)
nft add rule inet filter input tcp dport 8080 accept
日常使用中,其实不用太纠结底层是 iptables 还是 nftables。因为 firewalld 已经对两者做了抽象,你在 firewall-cmd 层面操作就行了。但知道底层机制可以帮助你理解:为什么有时候 iptables -L 看不到任何规则却还是不通——因为规则可能在 nftables 里。
4.4 验证防火墙是否挡住的三个思路
注意:排查防火墙问题时,务必先在服务器本机验证服务是否监听正常,再从外部测试连通性,最后检查防火墙。顺序不要颠倒,否则会浪费大量时间。
本机验证:
bash复制curl -v http://127.0.0.1:8080
如果在服务器本机用 curl 访问没问题,说明服务本身是正常的,问题出在网络链路上。然后从外部机器测试:
bash复制# 用 nc 测试端口连通性
nc -zv <服务器IP> 8080
# 用 telnet 测试
telnet <服务器IP> 8080
如果本机能通、外部不通,那基本可以断定是防火墙问题。这时候逐个关掉防火墙做对比测试:
bash复制# 临时停掉 firewalld(生产环境慎用)
systemctl stop firewalld
注意,这只是临时关闭,重启后会自动开启。测试完记得恢复:
bash复制systemctl start firewalld
如果关闭防火墙后外部访问正常,说明确实是防火墙规则问题,回到 4.1 和 4.2 的方案去核对规则。
5. 端口与连接状态:理解连接生命周期
端口排查中,我经常看到有人对着 ss -ant 的输出一脸懵,看到一堆 TIME_WAIT 就觉得服务器出了问题。这里补一节连接状态的基础知识,方便后续排查。
5.1 TCP 连接状态速览
一条 TCP 连接从建立到断开,会经历多个状态。日常排查中见得最多的四个:
- LISTEN:服务端在监听端口,等待连接。
- ESTABLISHED:连接已建立,正在传输数据。
- TIME_WAIT:主动关闭连接的一方在等待 2MSL(Max Segment Lifetime,报文最大生存时间)后才会彻底关闭这个连接。
- CLOSE_WAIT:被动关闭连接的一方收到了对方的 FIN,但本地应用程序还没调用 close 关闭 socket。
一个常见误区是看到大量 TIME_WAIT 就紧张。实际上,TIME_WAIT 是 TCP 协议的正常机制,目的是确保最后一个 ACK 能可靠到达对端,避免旧连接的延迟报文干扰新连接。在高并发的短连接场景(比如 Nginx 代理大量请求)中,TIME_WAIT 多是正常现象。
相反,CLOSE_WAIT 大量堆积才需要警惕。它意味着程序没有正确释放 socket,通常是代码里没有正确关闭连接。ss -ant | grep CLOSE_WAIT | wc -l 如果这个数字持续增长,基本可以断定应用层有连接泄漏。
5.2 用 ss 分析连接分布
快速统计当前所有连接状态的数量:
bash复制ss -ant | awk 'NR>1 {print $1}' | sort | uniq -c
输出类似:
code复制 5 ESTAB
3 LISTEN
128 TIME_WAIT
2 CLOSE_WAIT
这套组合命令(awk + sort + uniq)本身也是 Linux 文本处理三大利器的典型用法。看到 CLOSE_WAIT 增多,配合 ss -antp 查看对应进程,基本能定位到具体是哪个程序在泄漏连接。
5.3 连接超时与重试的参数调优
如果服务属于高并发短连接场景,TIME_WAIT 数量确实多到影响性能(比如端口不够用了),可以考虑调整内核参数:
bash复制# 允许 TIME_WAIT 状态的 socket 被重用
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
# 加快 TIME_WAIT 的回收
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
但是——这里要提醒一句,tcp_tw_recycle 在 NAT 环境下会引发严重的连接问题,因为 NAT 后面多台机器共用一个出口 IP,时间戳校验会导致部分连接被丢弃。实际上很多内核版本已经移除了这个选项。所以我的建议是:除非你知道自己在做什么,否则动内核网络参数时保持克制,先用 tcp_tw_reuse 观察效果。
6. 高频实用命令串烧:scp、find、rm 的常见坑
端口排查是主题,但既然都到第十三篇了,顺手把前面没展开讲、但被搜索得最多的几个高频命令一起收个尾。这些命令单看都不难,难在“什么时候用哪个”和“别踩哪些坑”。
6.1 scp 与 rsync 的选择
文件传输是运维的日常操作。scp 简单直接,基于 SSH 加密传输:
bash复制# 上传本地文件到服务器
scp ./backup.tar.gz user@192.168.1.10:/data/backup/
# 下载服务器文件到本地
scp user@192.168.1.10:/data/log/app.log ./
# 递归传输目录
scp -r ./conf/ user@192.168.1.10:/etc/app/
但如果你要传大文件、目录结构复杂、或者需要断点续传,建议用 rsync:
bash复制# 增量同步目录(-a 归档模式,-v 显示详情,-P 显示进度并支持断点续传)
rsync -avP ./data/ user@192.168.1.10:/data/
# 在服务器之间同步
rsync -avP user@192.168.1.11:/var/log/ /data/log/
rsync 的增量传输机制使它在大目录同步场景下比 scp 快很多。它先比较源和目标的差异,只传变化的部分。我第一次用 rsync 同步一个 50GB 的日志目录时,第二次同步只用了十几秒,当时就决定以后大文件都用它。
6.2 find 定位文件的高频姿势
find 是我使用频率最高的命令之一。常用组合:
bash复制# 按文件名查找
find / -name "nginx.conf"
# 按文件名模糊查找(忽略大小写)
find /etc -iname "*.conf"
# 按文件大小查找(大于 100MB 的文件)
find / -type f -size +100M
# 按修改时间查找(最近 7 天内改过的文件)
find /var/log -mtime -7
# 找到并直接删除(慎用!)
find /tmp -name "*.log" -mtime +30 -delete
关于 find 有一个经典坑:当文件名包含空格时,用 -exec 处理会出现问题。比如:
bash复制# 遇到空格文件名的文件会报错
find . -name "*.txt" -exec rm {} \;
正确姿势是用 -delete 参数,或者配合 -print0 和 xargs -0:
bash复制find . -name "*.txt" -delete
find . -name "*.txt" -print0 | xargs -0 rm
这个坑我踩过不止一次。批量清理日志文件时,遇到文件名带空格(比如 “access log 2024.txt”),-exec rm {} 直接报错,文件没删掉还刷了一屏错误信息。
6.3 rm 删除的安全操作规范
说到删除,rm 是 Linux 上最危险也最常用的命令之一。删错文件的经典案例相信每个人都听过不少。我的建议是:
- 删除目录用
rm -rf前,先ls确认路径没错。 - 重要操作前用
pwd确认当前目录。 - 能用
mv移动到/tmp目录代替直接删除,给自己留后悔药。
bash复制# 安全删除:先移动到临时目录
mv ./danger-dir /tmp/trash/
# 确认没问题后再真正删除
rm -rf /tmp/trash/danger-dir
我在生产环境操作时养成的习惯是:带 -rf 的命令绝不手敲,都是复制粘贴,防止肌肉记忆导致误删。说句不好听的,再熟的老手也可能在凌晨三点的割接中手抖。
7. 从一次真实故障复盘端口排查全流程
最后用一次真实故障来做整体复盘,把前面所有内容串起来。
事件背景:某个测试环境的应用升级后,通过浏览器访问管理后台一直提示连接被拒绝。这个应用监听在 9090 端口,对应了网上那个热搜词“linux的9090端口什么再用”。
我的排查步骤:
第一步,上服务器确认端口状态:
bash复制ss -lnt | grep 9090
结果无输出,说明 9090 端口没有进程在监听。这就说明问题不在防火墙,而是服务本身没起来或者监听失败了。
第二步,查看进程是否存在:
bash复制ps aux | grep java | grep -v grep
发现 Java 进程确实存在。说明可能是服务启动失败,端口绑定没生效。
第三步,查看应用日志:
bash复制journalctl -u myapp --since "10 minutes ago" | grep -i error
日志中发现了关键报错:BindException: Address already in use。这就矛盾了——ss -lnt | grep 9090 明明查不到监听。
第四步,怀疑是端口被非 TCP 协议占用,或者被其他网络命名空间占用。用 lsof 再查一遍:
bash复制lsof -i:9090
仍然没有输出。这时候想到一个可能:端口被其他服务监听在 IPv6 地址上,而我刚才只看了 IPv4。查看所有监听:
bash复制ss -lnt6 | grep 9090
果然,输出显示 [::]:9090 在监听。这是 IPv6 的监听地址,表示对所有 IPv6 地址生效。而 Java 应用默认尝试绑定 IPv4 的 9090,就被系统视为“地址已被占用”。
第五步,确认占用进程:
bash复制lsof -i6:9090
显示是另一个遗留的 Node.js 测试服务占用了 IPv6 的 9090 端口。最终处理:停掉遗留服务,启动新应用,问题解决。
这个案例想说明的是:端口排查中,IPv4 和 IPv6 的监听是分开的,ss -lnt 只显示 IPv4 的话,很可能漏掉 IPv6 的占用情况。排查时直接 ss -lntp(不带 4 或 6 限制)或者把 ss -lnt 和 ss -lnt6 都跑一遍,是更稳妥的做法。
根据个人经验,在写这套系列的过程中,我发现大多数端口和网络问题都不是“命令不会用”,而是“排查链路不完整”或者“对底层机制理解有偏差”。把 ss、lsof、firewall-cmd、netstat 这些工具组合成一套自己的方法论,比单纯积累命令数量重要得多。希望你读完这篇十三弹,再遇到端口类问题,能少走点弯路。
