2、端口占用的常见症状:连接失败、超时、服务不可用
端口被占用了,你的 TLS 连接会表现出什么样子?
很多人以为会直接弹个「端口被占用」的提示。其实不然。真实场景下,症状往往更隐蔽。我排查过不下百起 TLS 连接问题,其中大概有三成,根因就是端口占用。但客户报过来的现象五花八门——有的说连不上,有的说超时,有的干脆说服务挂了。
说白了,端口占用不会自己报名字。它只会通过三种典型症状表现出来。你只要掌握了这三种症状的特征,就能在茫茫日志中一眼把它揪出来。
2.1 症状一:连接失败(Connection Refused)
这是最直接的症状。客户端尝试建立 TCP 连接,结果被对方内核直接拒绝。
为什么会这样?
你想想看,服务端进程要监听一个端口,得先调用 bind() 系统调用。如果这个端口已经被别的进程占用了,bind() 就会返回 EADDRINUSE 错误。服务端进程根本起不来,端口上自然没有人在监听。客户端发 SYN 过来,内核一看没人接,直接回一个 RST 包。
客户端拿到的就是 Connection refused(连接被拒绝)。
关键特征:
- 客户端几乎瞬间报错(毫秒级)
- 错误信息明确包含 "Connection refused" 或 "ECONNREFUSED"
- 服务端进程可能已经启动失败,检查进程列表会发现目标进程不存在
我在项目中遇到过这样一个案例:运维同事重启 Nginx 后,客户端一直报连接被拒绝。他检查了 Nginx 进程,发现确实在运行。折腾了半小时,最后我用 ss -tlnp | grep 443 一看,443 端口被另一个旧的 Nginx 进程占着,新进程根本没 bind 上去。嗯,这就是典型的「进程在,端口不在」的坑。
2.2 症状二:连接超时(Connection Timeout)
这个症状比连接拒绝更让人头疼。客户端发 SYN 包过去,服务端既不拒绝,也不应答。客户端就一直等,等到内核的 TCP 超时时间耗尽,才报超时。
为什么会这样?
端口被占用,但占用的进程不是你想连的那个。比如你的 TLS 服务监听 8443,但另一个进程(比如一个调试用的 HTTP 服务)也监听在 8443 上。你的客户端发 SYN 过去,那个「冒牌」进程的内核收到了。但那个进程根本不认识你的 TLS 握手,不会回 SYN-ACK,也不会回 RST。它直接把包丢了。
客户端就只能干等。
注意:连接超时不一定都是端口占用。防火墙丢包、路由不通、服务端负载过高都可能导致超时。但如果你发现超时时间固定(比如 Linux 默认的 20 秒左右),而且服务端进程确实存在,那端口占用的嫌疑就很大。
我记得有一次线上告警,说支付接口超时。我查了服务端进程,正常。查了防火墙策略,正常。最后用 tcpdump 抓包一看,SYN 包到了服务端,但服务端没回包。再用 lsof -i :443 一看,443 端口被一个残留的 Python 测试脚本占着。那个脚本只监听不处理,所有连接都超时。这种「幽灵进程」最坑人。
2.3 症状三:服务不可用(Service Unavailable)
这个症状最迷惑人。端口没报错,连接能建立,TLS 握手也能完成,但业务就是跑不起来。
为什么会这样?
端口被占用,但占用的进程恰好也是一个 TLS 服务。比如你部署了两个 Web 服务器,一个监听 443,另一个也监听 443。后启动的那个会 bind 失败,但先启动的那个正常工作。客户端连上来,TLS 握手成功,HTTP 请求发过去,返回的却是另一个应用的页面。
用户看到的就是「服务不可用」——页面内容不对,接口返回 404,或者证书校验失败。
我的排查习惯:遇到服务不可用,先别急着看应用日志。先确认你连的端口上到底跑的是哪个进程。用 curl -v https://目标IP:端口 看看证书信息,如果证书域名对不上,十有八九是端口被别的服务占了。
我曾经帮一个团队排查过:他们的 HTTPS 接口偶尔返回 502。查了三天应用代码,毫无头绪。最后我用 openssl s_client -connect host:443 一看,返回的证书是另一个域名的。原来运维在同一个端口上启动了新旧两个版本的 Nginx,旧版本先占住了 443,新版本启动失败但没人发现。客户端有时连到旧版本,有时连到新版本(因为负载均衡),导致行为不一致。
2.4 三种症状的对比与快速定位
为了方便你快速判断,我把三种症状整理成了表格。你遇到问题时,对照着看就行。
| 症状 | 客户端表现 | 服务端表现 | 最可能的原因 | 排查切入点 |
|---|---|---|---|---|
| 连接失败 | 瞬间报错,ECONNREFUSED | 目标进程不存在或 bind 失败 | 端口被占,目标进程未启动 | ss -tlnp | grep 端口 |
| 连接超时 | 等待 20s+ 后报超时 | 进程存在但不处理连接 | 端口被无关进程占用 | lsof -i :端口 + tcpdump |
| 服务不可用 | 连接成功,但业务异常 | 进程存在,但服务不对 | 端口被另一个同类服务占用 | openssl s_client 检查证书 |
2.5 核心逻辑:从症状到根因的排查路径
下面这张图,是我自己总结的排查路径。你照着走,基本不会漏掉端口占用的问题。
这张图的核心思路很简单:先看客户端报什么错,然后对号入座,用对应的命令去查端口占用情况。如果确认端口被占,就找到占用进程,杀掉或改配置。如果端口没被占,再去排查防火墙、路由、应用代码等其他原因。
我个人习惯把这张图打印出来贴在工位上。每次遇到 TLS 连接问题,先走一遍这个流程,能省下大量瞎猜的时间。