Skip to content
Go back

服务端正常启动但客户端请求不到:网络可达性排查全链路

服务端正常启动但客户端请求不到:网络可达性排查全链路

一句话结论(30s)

服务端「启动正常但连不上」90% 的问题不在代码,而在网络可达性链路——因为从 IP 层到端口层到防火墙到监听地址到 SELinux 再到容器/代理,任何一层拦截都会让请求到不了服务,所以应按 ping→telnet→防火墙→监听→SELinux→代理 的清单逐层排查,而非盲目重启。

核心原理(2min)

底层深入(5-10min)

开发环境调试时碰到的经典场景:服务端显示”Started Application in 5.6 seconds”,一切都正常,客户端却连不上。日志干干净净,没有错误也没有异常——问题不在代码,在代码写的代码之外。

第一关:IP层是否可达 —— ping

首先要回答的问题是——两台机器之间能不能通信?

ping <server_ip>

ping通了说明IP层没问题。如果ping不通:

注意:ping使用的是ICMP协议,不是TCP或UDP。ping通只能证明IP层可达,不能证明TCP端口可达。

思考:为什么「ping 通了」还不能说明问题?因为 ping 走的是 ICMP,TCP 端口走的是另一条链路。ping 通只证明「IP 层可达、机器还活着」,但目标端口的监听、防火墙对端口的放行是另一回事——就好比电话拨通(IP 通)不代表对方接了你想找的那个分机(端口通)。

第二关:端口是否可达 —— telnet / nc

服务监听的是TCP端口,ping通了不代表端口也通。

telnet <server_ip> <port>
# 或
nc -zv <server_ip> <port>

telnet连接成功(显示Connected / Escape character)说明TCP三次握手完成,端口层可达。如果连接失败(Connection refused),说明端口没监听;如果卡住不动(连接超时),说明包被中间某个设备丢弃了——大概率是防火墙。

思考:为什么 Connection refused 和「连接超时」指向完全不同的结论?因为 refused 是「对方机器明确回了 RST」——说明机器通、但那个端口没人监听;超时是「发出去的包石沉大海」——说明包被中间某个设备(大概率防火墙)悄悄丢掉了。一个告诉你「服务没起来」,一个告诉你「路上有拦截」,排查方向截然不同。

第三关:防火墙策略 —— iptables / firewalld

这是最常见的罪魁祸首。Linux上的防火墙规则可能非常复杂:

# 先看防火墙状态
systemctl status firewalld   # 或 ufw status
# 检查iptables规则
iptables -L -n -v             # filter表
iptables -t nat -L -n -v      # NAT表
# 检查是否开了对应端口
firewall-cmd --list-all       # firewalld方式

重点看三条链:

常见防火墙陷阱:

第四关:服务到底监听在哪 —— netstat / ss

服务启动成功不代表监听对了地址和端口:

netstat -tlnp | grep <port>       # 传统工具
ss -tlnp | grep <port>            # 更快的ss

重点看Local Address这一列:

思考:为什么监听 127.0.0.1 就「外部无法访问」?因为回环地址只存在于本机内部,代表「这台机器自己」。服务绑到回环上,等于只对本机进程开放;外部请求的包到达网卡后,内核发现目的地不是本机监听的任何「对外地址」,直接丢弃。很多框架默认绑定 127.0.0.1,正是「本地能访问、外部连不上」的高频元凶。

第五关:SELinux —— 隐藏的访问控制

在CentOS/RHEL系统上,SELinux是另一道难以察觉的屏障:

getenforce                 # 查看SELinux状态
semanage port -l | grep http  # 查看SELinux允许的端口

SELinux有自己的端口白名单。例如,HTTP服务默认只允许80和443端口。如果你把Nginx改到8080端口,iptables放行了,但SELinux依旧拦截,客户端也连不上。

快速验证是否是SELinux的问题:

setenforce 0    # 临时关闭(仅测试用,不要在生产环境这样做)
# 如果能连了,就是SELinux问题,需要添加策略而非永久关闭
semanage port -a -t http_port_t -p tcp 8080  # 正确做法

第六关:网络代理与NAT

如果服务在容器(Docker/K8s)里运行,排查链路更长:

如果客户端经过了代理(公司代理/Nginx反向代理/API网关),也要检查代理是否把请求转发到了正确的地方。

排查之外:建立”可达性心理清单”

每次遇到”连不上”,不要盲目重启服务或重启服务器。按顺序走一遍:

ping通了吗? → telnet通了吗? → 防火墙放行了吗? 
→ 监听地址对吗? → SELinux关闭/配置了吗? → 代理/容器配置正确吗?

这六个问题,花两分钟逐项过一遍,比反复重启、改配置、然后怀疑人生有效得多。建一个自己的排查备忘录,遇到问题先查这个——90%的”服务正常但连不上”都能在这六个环节找到答案。

章末提问

Q1:服务端正常启动但客户端连不上,你的排查思路是什么?

结论先行:按「可达性链路」逐层排查:ping(IP 层)→ telnet/nc(端口层)→ 防火墙 → 监听地址 → SELinux → 代理/NAT。因为「连不上」90% 是网络可达性问题而非代码问题,任何一层拦截都会让请求到不了服务,逐层排除能用最小代价定位 90% 的故障。

Q2:telnet 报 Connection refused 和连接超时,分别说明什么问题?

结论先行:refused 说明端口没监听,超时说明包被中间设备丢弃(大概率防火墙)。因为 refused 是对方机器回了 RST——机器通但目标端口无人监听;超时是 SYN 发出去没回应——机器可能通但请求被防火墙静默丢弃,两者指向的排查方向完全不同。

Q3:为什么服务监听 127.0.0.1 时外部访问不到?

结论先行:因为回环地址只在本机内部有效,绑定它等于只对本机进程开放。因为外部请求到达网卡后,内核发现目的地址不是本机监听的任何对外地址,直接丢弃;所以对外服务必须监听 0.0.0.0(所有接口),这是很多框架默认绑 127.0.0.1 导致的经典坑。


Share this post on:

Previous Post
网页慢转圈排查:从物理层到应用层的分层诊断
Next Post
服务端大量TIME_WAIT:原因、危害与解决方案