ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

服务器列表获取失败排查:从网络不可达到联机恢复

服务器列表获取失败排查:从网络不可达到联机恢复 如果你平时经常接触多人联机游戏、局域网组队工具或者社区服务器管理一定对“服务器列表”不陌生。在很多工具里服务器列表是进入游戏的第一步客户端从一个“列表服务”中拉取当前可用的房间、节点或者服务器地址然后你才能挑选一个进入。最近我在调试一套名为 SquadLink 的服务器列表模块时反复遇到同一条报错从服务器获取共享列表失败:网络不可达。网上资料很零散有人说是服务器炸了有人说是版本不匹配也有人说是网络问题。为了彻底解决这个问题我把服务器列表的获取原理、网络排错流程和客户端兜底方案完整整理了一遍。本文会从概念讲起逐步拆解报错根因并给出可复制的代码和命令无论是刚入门的新手还是负责联机服务运维的开发者都可以直接参考。1. 背景与核心概念1.1 什么是服务器列表服务器列表在广义上是一个“可连接节点的清单”。它常见于以下场景游戏内的服务器浏览器例如射击游戏、沙盒游戏中的社区服务器列表联机组队工具中的“房间列表”内网开发环境中的服务注册与发现页面游戏模组或工具中的“共享服务器”模块。从技术实现上看服务器列表通常包含两类信息服务器节点的基础信息如名称、IP、端口、地区、当前在线人数服务器运行状态例如地图名、模式、版本号、延迟、是否满员。客户端拿到列表后会把数据渲染到界面上。你点击某个条目时客户端才会拿着对应的地址去连接游戏服务器。所以“服务器列表”本身不承担游戏流量转发它更像是一本“通讯录”。一旦这本通讯录获取失败客户端就不知道有哪些节点可以连自然也就进不了游戏。1.2 SquadLink 服务器列表指的是什么SquadLink 这个名称看起来与多人小队作战类产品有关。在项目实践中它可能指以下三种情况之一一款游戏模组或客户端内置的服务器列表模块一个独立的小队组队工具通过服务器列表展示队友或社区节点一套开源的联机服务器查询组件常见于游戏服务器管理后台。不管它具体是哪种形态服务器列表获取的链路是相似的。本文不会绑定某一个具体游戏而是以 SquadLink 服务器列表为例讲解通用架构和排错方法。这样即使你用的是其他工具也可以套用同样的思路。1.3 “从服务器获取共享列表失败:网络不可达”的含义这条报错信息可以拆成三部分理解“从服务器获取”客户端主动向某个远程服务器发起了 HTTP 或 TCP 请求“共享列表”服务器端返回的公共节点列表可能被多个客户端共享使用“网络不可达”客户端在 TCP 连接阶段就失败了也就是说客户端连目标服务器 IP 的端口都连不上。换句话说这不是“数据格式不对”也不是“JSON 解析失败”而是网络层就断了。常见的具体原因包括域名解析失败DNS 查询不到对应 IPTCP 连接超时目标服务器无响应端口被防火墙拦截客户端所在网络无法访问目标服务器服务器列表服务本身宕机系统代理配置异常导致请求没有正确发出。理解这条报错是理解整篇文章的关键。下面我会先讲清楚服务器列表的获取链路再一步步演示如何排查“网络不可达”。2. 环境准备与版本说明2.1 本文适用环境本文示例不依赖特定操作系统Windows、Linux、macOS 均可。示例代码使用 Python 编写因为 Python 在网络诊断和脚本验证方面非常方便。版本需要根据你的项目实际情况调整本文并不绑定某个具体框架版本。示例以常见环境为例Python 3.8 及以上依赖库requests、Flask系统命令行工具ping、curl、nslookup、telnet 或 Test-NetConnection编辑器或 IDE 不做限制VSCode、PyCharm 均可。如果你的项目不是 Python 技术栈也不要紧。核心排查思路是通用的命令部分可以直接套用。2.2 准备工具建议提前准备好以下几类工具后面排查时会反复用到工具作用ping测试目标 IP 是否可达判断网络连通性nslookup检查域名解析是否正常telnet测试指定 IP端口是否能建立 TCP 连接curl直接请求 HTTP 接口观察响应状态Test-NetConnectionWindows 下替代 telnet 的端口测试工具Wireshark 或 tcpdump抓包分析请求是否发出、响应是否回来安装 Python 依赖的命令如下pip install requests flask如果你是 Windows 用户在 PowerShell 中执行即可。下面开始进入正题。3. 服务器列表获取机制拆解3.1 服务器列表的两种常见形态服务器列表在架构上主要分两种。第一种中心化列表服务。客户端启动后向一个固定的中心服务器请求列表。中心服务器负责收集、缓存、下发所有游戏服务器信息。优点列表来源统一更新及时可以做筛选和排序 缺点中心服务器一旦挂掉所有客户端都拿不到列表。SquadLink 服务器列表如果报“网络不可达”大概率就是这种中心化架构出了问题。第二种去中心化列表。客户端通过局域网广播、UDP 扫描或 P2P 网络发现其他节点再聚合出列表。这种架构不依赖单一服务器但穿透 NAT、内网发现、数据一致性都比较复杂通常用于局域网联机或小型工具。无论是哪种形态客户端都会有一个“获取列表”的入口函数。报错信息“从服务器获取共享列表失败:网络不可达”通常出现在中心化架构中。3.2 获取流程拆解一次完整的服务器列表获取流程可以拆成下面几个步骤客户端根据配置文件读取列表服务器地址对列表服务器域名做 DNS 解析与列表服务器的 IP端口建立 TCP 连接发送 HTTP 请求通常是 GET 方式列表服务器返回 JSON 或 XML 数据客户端解析数据渲染到界面用户点击某个服务器客户端再直连该游戏服务器。用文字描述会更直观客户端 - DNS 解析example.com - 1.2.3.4 - TCP 连接1.2.3.4:8080 - HTTP GET /api/server/list - JSON 数据 - 渲染列表“网络不可达”可能出现在第 2 步、第 3 步或第 4 步。第 2 步失败通常报 DNS 解析错误第 3 步失败通常报 Connection Refused、Timeout 或 Network is unreachable第 4 步失败可能是请求被重置或超时。所以排查时我们要一层一层验证。3.3 “网络不可达”的几个层级第一层DNS 解析层。如果域名解析不了客户端拿不到 IP自然无法连接。检查方式nslookup your-server-domain.com如果返回Non-existent domain或超时说明域名解析有问题。第二层TCP 连接层。IP 能解析但不代表端口能连通。防火墙、安全组、服务器未监听端口都会导致 TCP 层不可达。检查方式telnet your-server-domain.com 8080或者使用 Windows 下的命令Test-NetConnection your-server-domain.com -Port 8080第三层HTTP 应用层。TCP 能连通但 HTTP 请求失败比如 404、500、403也会被某些客户端统一封装为“获取列表失败”。不过这种通常不是“网络不可达”而是 HTTP 错误。如果报错明确写“网络不可达”优先排查前两层。4. 完整实战案例模拟服务器列表请求与排查这一节我们会搭建一个本地的服务器列表服务然后用 Python 客户端请求它最后模拟“网络不可达”场景并完成排查。整套流程可以在你自己的电脑上完整复现。4.1 编写一个最小的列表服务器为了还原 SquadLink 服务器列表的场景我们先用 Flask 写一个简化版列表服务。它的接口路径是/api/server/list返回一个 JSON 数组。# 文件路径server.py from flask import Flask, jsonify app Flask(__name__) SERVER_LIST [ { id: 1, name: SquadLink 亚洲节点 01, address: 192.168.1.10, port: 27015, players: 32, max_players: 64, map: desert_01, mode: conquest }, { id: 2, name: SquadLink 亚洲节点 02, address: 192.168.1.11, port: 27015, players: 18, max_players: 64, map: forest_02, mode: domination } ] app.route(/api/server/list, methods[GET]) def get_server_list(): return jsonify({ code: 0, message: success, data: SERVER_LIST }) if __name__ __main__: app.run(host0.0.0.0, port8080, debugTrue)运行方式python server.py正常情况下你访问http://127.0.0.1:8080/api/server/list会看到 JSON 数据。4.2 编写客户端获取逻辑并处理异常接下来写一个客户端脚本模拟 SquadLink 获取共享列表的操作。这里会加入超时、重试和异常分类。# 文件路径client.py import requests import sys LIST_API http://127.0.0.1:8080/api/server/list TIMEOUT 5 RETRY_TIMES 2 def fetch_server_list(url: str) - list: for attempt in range(RETRY_TIMES 1): try: resp requests.get(url, timeoutTIMEOUT) resp.raise_for_status() payload resp.json() if payload.get(code) ! 0: raise RuntimeError(f业务返回失败: {payload.get(message)}) return payload.get(data, []) except requests.exceptions.DNSFailure as exc: print(f[第 {attempt 1} 次] DNS 解析失败: {exc}) break except requests.exceptions.ConnectionError as exc: print(f[第 {attempt 1} 次] 网络不可达或连接失败: {exc}) if attempt RETRY_TIMES: print(等待 1 秒后重试...) time.sleep(1) except requests.exceptions.Timeout as exc: print(f[第 {attempt 1} 次] 请求超时: {exc}) if attempt RETRY_TIMES: print(等待 1 秒后重试...) time.sleep(1) except Exception as exc: print(f[第 {attempt 1} 次] 未知异常: {exc}) break return [] if __name__ __main__: import time servers fetch_server_list(LIST_API) if not servers: print(获取服务器列表失败请检查网络或列表服务状态。) sys.exit(1) print(f共获取到 {len(servers)} 台服务器) for s in servers: print(f {s[name]} | {s[address]}:{s[port]} | 人数 {s[players]}/{s[max_players]})运行结果预期如下共获取到 2 台服务器 SquadLink 亚洲节点 01 | 192.168.1.10:27015 | 人数 32/64 SquadLink 亚洲节点 02 | 192.168.1.11:27015 | 人数 18/64注意代码里的DNSFailure在 requests 库中并不存在真实环境下应该使用requests.exceptions.ConnectionError统一捕获然后根据异常信息判断具体类型。上面的示例是为了展示不同层级的异常定位思路在实际项目里建议这样简化except requests.exceptions.ConnectionError as exc: if isinstance(exc, requests.exceptions.ProxyError): print(代理连接失败请检查系统代理配置。) else: print(网络不可达请检查网络。)4.3 模拟“网络不可达”并定位问题现在我们把列表服务器停掉再次运行客户端python client.py大概率会看到类似下面的输出[第 1 次] 网络不可达或连接失败: HTTPConnectionPool(host127.0.0.1, port8080): Max retries exceeded with url: /api/server/list (Caused by NewConnectionError(requests.adapters.HTTPAdapter object at ...: Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝无法连接。))这个错误信息其实已经告诉你了目标端口没有服务在监听。这就是一次典型的“连接不可达”复现。在真实环境中你拿到的报错可能是Network is unreachable网络不可达表示本机路由无法到达目标网络也可能是timed out超时表示请求发出去了但没有响应。这两者原因不同Network is unreachable本机路由表里面根本没有去往目标 IP 的路径常见于静态 IP/内网环境配置错误timed out数据包发出去了但目标没有回应常见于防火墙丢包或服务器宕机。排查时按下面的顺序逐个验证。第一步验证本机网络。ping 8.8.8.8注意这里只是用公网 IP 验证本机是否具备外网连通性。如果你所在的网络环境不允许 ping 外网可以换成ping 你的列表服务器IP。如果 ping 不通说明本机网络就有问题。第二步验证域名解析。nslookup your-server-domain.com如果 DNS 无法解析先检查本机 DNS 配置。第三步验证目标端口。telnet your-server-domain.com 8080如果 telnet 无法连接说明目标端口不可达需要检查目标服务器防火墙或云安全组。第四步验证 HTTP 接口。curl -v http://your-server-domain.com/api/server/listcurl 会输出完整的请求过程包括 DNS 解析耗时、TCP 连接耗时、HTTP 响应状态码。这是定位问题最高效的命令之一。4.4 常见修复动作根据排查结果采取对应动作定位结果修复动作DNS 解析失败修改本机 DNS 为 223.5.5.5 或 114.114.114.114 后再测试目标端口不可达在服务器侧放行对应端口或检查列表服务是否监听在 0.0.0.0本机无外网检查网线、Wi-Fi、路由器、静态 IP 配置系统代理异常关闭系统代理或把列表服务域名加入代理白名单服务器宕机通过进程管理工具重启列表服务检查日志防火墙拦截临时关闭防火墙测试确认后添加放行规则超时时间过短在客户端代码中调大超时时间并增加重试机制这里特别提醒服务器列表服务如果突然从“正常”变成“网络不可达”优先看服务器负载和进程状态。很多情况下不是网络断了而是列表服务进程崩溃或假死导致端口无法响应。5. 常见问题与排查思路在实际项目中SquadLink 服务器列表的“网络不可达”往往会以不同形式出现。下面整理了一个排查表格大家按顺序对照即可。问题现象常见原因解决思路报错Network is unreachable本机路由表缺少目标网络路由检查本机 IP、网关、路由配置报错Connection timed out目标服务器防火墙丢包或线路不通使用 ping 和 telnet 测试目标 IP 和端口报错Connection refused目标端口没有服务监听或监听地址错误检查进程是否启动服务是否监听在 0.0.0.0报错Temporary failure in name resolutionDNS 解析失败修改 DNS 配置重新测试 nslookup内网启动正常外网无法获取列表服务器没有公网 IP或安全组未放行使用公网 IP 或做端口映射检查云安全组部分玩家无法获取列表部分正常地区线路差异或客户端代理配置差异使用多节点列表服务或检查客户端代理设置高峰期偶尔报网络不可达列表服务并发承载不足增加列表服务实例配置负载均衡和缓存更新版本后报网络不可达版本不匹配列表服务接口变更确认客户端和服务端接口路径、参数是否一致这里再补充一个容易被忽略的点很多联机工具在启动时会同时请求多个服务器列表源如果其中一个源超时可能会阻塞整个列表渲染。解决办法是给每个请求设置独立的超时时间并且使用异步并发请求避免一个慢节点拖垮全部。6. 最佳实践与工程建议6.1 客户端侧建议所有网络请求必须设置超时。不要使用默认的无限超时否则界面会长时间卡住。增加重试机制但需要带退避策略。推荐第一次重试等待 1 秒第二次等待 2 秒最多 3 次。对列表数据做本地缓存。即使网络不可达也可以先展示上一次成功的列表数据并提示“列表数据可能不是最新”。区分错误类型。不要在 UI 上把所有失败都叫“网络不可达”应区分 DNS 错误、超时、拒绝连接、服务端错误。记录日志。日志中必须包含请求 URL、耗时时长、异常类型、异常详情方便线上排查。如果客户端支持代理需要提供“不使用代理”或“代理白名单”选项。因为系统代理配置错误时最容易出现网络不可达。6.2 服务端侧建议列表服务必须支持健康检查例如暴露/healthz接口。接口响应时间要可控。如果列表数据量很大建议使用分页或增量拉取。使用缓存降低数据库压力。可以给列表接口加 5 到 10 秒的缓存因为服务器列表并不需要每毫秒更新。部署至少两个节点避免单点故障。前面接入负载均衡后端列表服务滚动重启时用户无感知。接口变更要兼容旧版本客户端。可以在接口中保留version字段客户端根据版本决定是否使用新字段。所有服务器节点信息在下发前做脱敏和校验避免把内网 IP、服务器管理端口暴露给所有客户端。6.3 生产环境变更注意事项修改服务器列表接口、切换列表服务域名、调整端口或协议时必须先在测试环境完整验证再逐步灰度到生产环境。特别是涉及数据库、防火墙和负载均衡的变更一定要提前备份配置并准备回滚方案。联机服务对实时性要求较高列表服务一旦变更失败所有客户端都会在短时间内无法进入游戏影响面较大。安全方面也要注意列表接口虽然只是下发服务器信息但在生产环境仍然应该设置合理的访问频控避免被恶意刷量导致服务不可用。如果列表中包含隐藏测试节点或管理节点必须严格过滤后下发最小化信息暴露范围。7. 总结与学习路线本文围绕 SquadLink 服务器列表展开核心解决了三件事。第一讲清楚了服务器列表的获取机制客户端需要完成 DNS 解析、TCP 连接、HTTP 请求三步才能拿到共享列表报错“网络不可达”意味着前两步出了问题。第二提供了一个完整的本地模拟环境包括 Flask 列表服务、Python 客户端、异常捕获和重试逻辑你可以直接运行复现问题。第三整理了一套系统的排查流程先 ping 验证本机网络再 nslookup 验证 DNS接着 telnet 验证端口最后 curl 验证 HTTP 接口。按照这个顺序绝大多数“网络不可达”问题都能定位到具体层级。接下来你可以继续深入学习以下内容HTTP 状态码与 TCP 三次握手细节DNS 解析原理与常见故障Wireshark 抓包分析网络不可达问题客户端异步并发请求列表的写法列表服务的负载均衡与高可用部署。动手实践是最好的学习方式。建议你现在就把上面的 Flask 服务跑起来分别尝试停掉服务、改错端口、关闭防火墙、填错域名观察客户端报错分别是什么样。把这些现象都记录一遍以后在真实项目中再遇到 SquadLink 服务器列表“网络不可达”你会比其他人更快定位问题。如果本文对你有帮助可以收藏备用也欢迎在实际排查中回来对照这个流程复核。
返回列表