「端口被占用了」「服务起不来报地址已被使用」「防火墙开了但连不上」——端口问题几乎每个部署日都会遇到。排查端口,需要回答四个问题:谁在监听、端口通不通、谁占用了、连接状态如何。这一篇用ss、lsof、nc、telnet、curl五把工具,串成一套端口排查的完整流水线,并讲清端口占用、连接拒绝、超时这几类问题的处理套路。
一、端口排查的四个问题
拿到一个端口号,先想清楚要查什么:
| 问题 | 工具 |
|---|---|
| 谁在监听这个端口? | ss -lntp/lsof -i |
| 端口从外面能连吗? | nc/telnet |
| 端口被谁占用了(起不来服务)? | lsof -i/fuser |
| 应用层返回什么? | curl |
思路:先看本机有没有监听 → 再看对方能不能连 → 再看应用是否正常。逐层排除。
二、ss:端口与连接的首选工具
ss(socket statistics)是现代 Linux 看端口和连接的首选,比netstat快得多(第 67 篇已介绍),这里聚焦「端口排查」的用法。
查看监听端口
sudoss-tlnpState 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=980)) LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1234)) LISTEN 0 128 127.0.0.1:3306 0.0.0.0:* users:(("mysqld",pid=2345))-tTCP,-l监听,-n数字,-p显示进程0.0.0.0:80监听所有网卡;127.0.0.1:3306只监听本地(外部连不上!)
⚠️ 监听地址决定能否被外部访问
这是「端口开着却连不上」的头号原因:
| 监听地址 | 含义 |
|---|---|
0.0.0.0:80或*:80 | 所有网卡,外部可连 |
127.0.0.1:3306 | 仅本机回环,外部连不上 |
192.168.1.10:80 | 仅该网卡 |
看到服务只监听127.0.0.1,那不管防火墙怎么放行,外部都连不上——要改服务的绑定配置(如 MySQL 的bind-address、Redis 的bind)。
精简输出
# 只看监听端口,不显示进程ss-tln# 简洁格式ss-tln|awk'{print $4}'|sort-t:-k2-n三、lsof:从进程反查端口
ss是从「端口」找进程,lsof反过来:从「进程」找它打开的端口和文件。
查看端口被谁占用
sudolsof-i:8080COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 12345 app 42u IPv6 1234567 0t0 TCP *:8080 (LISTEN)一眼看出 PID 12345 的 java 占了 8080。
常用查询
# 所有网络连接sudolsof-i# 所有 TCPsudolsof-iTCP# 某进程打开的所有文件/端口sudolsof-p12345# 某用户打开的网络连接sudolsof-i-uapp# 某状态sudolsof-i-sTCP:LISTENfuser:更快的端口占用查询
sudofuser8080/tcp8080/tcp: 12345fuser只输出 PID,速度更快,适合脚本。
四、nc / telnet:测试端口连通性
本机监听正常,还得测「从外部/另一端能不能连」。这是区分「服务问题」和「网络/防火墙问题」的关键。
nc(netcat)
# 测单端口nc-zv192.168.1.10080# 测一组端口nc-zv192.168.1.10020-80# 带超时(避免长时间卡住)nc-zv-w3192.168.1.10080# 从本机某个源端口测(排查源端口限制)nc-zv-s192.168.1.50192.168.1.10080Connection to 192.168.1.100 80 port [tcp/http] succeeded!telnet
telnet192.168.1.10080Connected to ...→ 端口开放Connection refused→ 端口没监听或被 REJECT- 长时间无响应 → 防火墙 DROP 或网络不通
⚠️ 三种结果对应三类问题
| 结果 | 含义 | 排查方向 |
|---|---|---|
succeeded/Connected | 端口可连 | 网络和端口都 OK,查应用 |
Connection refused | 端口没监听 | 服务没起 / 监听地址错 / 被 REJECT |
| 超时无响应 | 包被丢弃 | 防火墙 DROP / 网络不通 / 路由问题 |
refused 和超时的区别至关重要:refused 说明包到了目标、只是没人接;超时说明包根本没到。后者才是网络/防火墙问题。
用 nc 模拟服务端(测反向)
# 在 A 机监听nc-l9999# 在 B 机连接nc192.168.1.109999# 直接打字,A 机能收到,说明双向通畅五、curl:HTTP 层诊断
端口通了,还要确认 HTTP 应用正常。curl是最实用的 HTTP 测试工具。
基础测试
# 请求并显示响应头curl-Ihttp://192.168.1.100/# 显示详细过程curl-vhttp://192.168.1.100/# 跟随重定向curl-Lhttp://example.com/# 指定方法curl-XPOST-d'{"key":"value"}'-H"Content-Type: application/json"http://host/api# 只看 HTTP 状态码curl-o/dev/null-s-w"%{http_code}\n"http://host/用 -w 拆解各阶段耗时
curl-o/dev/null-s-w"dns:%{time_namelookup} connect:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total}\n"https://example.com/dns:0.011 connect:0.032 tls:0.098 ttfb:0.145 total:0.156各阶段含义:
| 指标 | 含义 |
|---|---|
time_namelookup | DNS 解析耗时 |
time_connect | TCP 连接耗时 |
time_appconnect | TLS 握手完成耗时 |
time_starttransfer | 首字节时间(TTFB) |
time_total | 总耗时 |
哪个阶段大,问题就在哪:DNS 慢查 DNS,connect 慢查网络,ttfb 慢查应用。
常用诊断选项
# 忽略证书(测试自签名)curl-khttps://host/# 指定 Host 头(测虚拟主机)curl-H"Host: example.com"http://1.2.3.4/# 指定网卡/源 IPcurl--interfaceeth0 http://host/# 显示响应时间curl-w"@curlformat.txt"-o/dev/null-shttp://host/六、端口被占用怎么处理
服务起不来报Address already in use,处理步骤:
# 1. 找到占用端口的进程sudolsof-i:8080# 或sudoss-lntp|grep:8080# 或sudofuser8080/tcp# 2. 确认是不是僵尸进程或重复启动ps-fp<PID># 3. 决定杀掉还是换端口sudokill<PID># 优雅终止sudokill-9<PID># 强杀(谨慎)# 4. 确认端口释放sudoss-lntp|grep:8080⚠️ TIME_WAIT 导致端口"被占用"
服务重启后立刻报端口占用,可能是上一个连接处于TIME_WAIT:
ss-tan|grep:8080|grepTIME-WAIT处理:服务端应设SO_REUSEADDR(大多数框架默认开启),或等待 60 秒(2MSL)自然释放。
七、⚠️ 常见错误
- 只看本机监听说"端口开了"。还要从对端
nc/telnet测,本机监听的127.0.0.1外部连不上。 refused和超时不分。refused 是服务没起(本地问题),超时是网络/防火墙(链路问题),方向完全不同。- 忽略了监听地址。服务绑在
127.0.0.1,却一直查防火墙。 - lsof 看不到进程。需要 root,普通用户看不到别人的进程。
- curl 不指定 Host 测虚拟主机失败。多站点服务器要根据 Host 头路由,直接 IP 访问可能返回默认站或 404。
- 测端口不带超时。
nc/telnet遇 DROP 会卡很久,加-w 3。 - 防火墙和安全组只看一个。云服务器有安全组 + 本机防火墙两层,都要放行。
curl正常但浏览器不行。可能是代理、证书、DNS 缓存等客户端侧问题。
八、原理探究:端口、套接字与四元组
端口是什么
IP 地址定位「哪台机器」,端口定位「机器上的哪个进程」。端口是 16 位,范围0~65535:
| 范围 | 用途 |
|---|---|
| 0~1023 | 众所周知端口(需 root 绑定) |
| 1024~49151 | 注册端口 |
| 49152~65535 | 动态/临时端口(客户端出站用) |
套接字与四元组
一条 TCP 连接由四元组唯一标识:
(源IP, 源端口, 目标IP, 目标端口)ss里每一个连接就是一条四元组。这也是为什么服务端0.0.0.0:80能同时接受成千上万个连接——每个客户端的四元组不同,内核靠四元组区分它们。
客户端临时端口
客户端发起连接时,内核从「临时端口范围」里分配一个源端口:
cat/proc/sys/net/ipv4/ip_local_port_range# 32768 60999高并发短连接场景下,这不到 3 万个端口可能被耗尽(大量 TIME_WAIT 占着),表现为「Cannot assign requested address」。解法:开启net.ipv4.tcp_tw_reuse(客户端侧)、用长连接、或调大端口范围。
监听套接字 vs 连接套接字
- 监听套接字:
ss -l看到的LISTEN,服务端listen()创建的,负责接受新连接。 - 连接套接字:三次握手完成后,内核为每条连接创建一个新的套接字,由四元组标识。
同一个服务端端口(如 80)对应一个监听套接字 + N 个连接套接字,这就是ss -tln只有一条 80、而ss -tan有大量 80 连接的原因。
理解了模型,排查就清晰了
- 服务起不来→ 看监听套接字能否创建(端口被占、权限不足)
- 外部连不上→ 看监听地址 + 防火墙 + 安全组
- 连上没响应→ 看连接套接字状态(SYN_RECV 卡住 = 网络问题)
- 连接太多→ 看四元组数量、临时端口、TIME_WAIT
九、端口排查速查表
# 1. 谁在监听端口sudoss-tlnp|grep:80sudolsof-i:80# 2. 端口被谁占用sudolsof-i:8080sudofuser8080/tcp# 3. 从外面测端口nc-zv-w3host80telnethost80# 4. HTTP 层测试curl-Ihttp://host/curl-o/dev/null-s-w"%{http_code}\n"http://host/curl-w"dns:%{time_namelookup} connect:%{time_connect} total:%{time_total}\n"-s-o/dev/null http://host/# 5. 看连接状态汇总ss-tan|awk'NR>1{print $1}'|sort|uniq-c|sort-rn# 6. 杀占用端口的进程sudokill$(sudolsof-t-i:8080)端口排查的主线记住:ss看谁在听 →lsof看谁占了 →nc/telnet测通不通 →curl测应用。而绝大多数「端口问题」,根因就三个:服务没起、监听地址错、防火墙没放行——对照结果类型(refused vs 超时)就能快速定位。