最后更新于:2026年7月

节点突然连不上了,是被墙了还是服务器挂了? 这是每个科学上网用户都会遇到的问题。很多人第一反应是——换节点、找客服、等恢复。但如果你能自己判断出问题所在,不仅能节省大量时间,还能在节点被墙的第一时间采取应对措施。
本文不是端口检测基础教程(基础版请移步 端口检测指南),而是节点存活检测的实战手册——从被墙的5种典型症状到自动检测脚本,手把手教你建立一套自己的节点健康监控体系。
【适合谁看?】
- 自建节点用户,想自己判断节点状态
- 机场用户,想在被墙前发现问题
- 技术爱好者,想写自动监控脚本
- 运维人员,管理多台代理服务器
一、节点被墙的5种典型症状
症状1:连接超时(Timeout)
表现: 客户端显示 “连接超时”、“i/o timeout”、“dial tcp timeout”
可能原因:
- 节点 IP 被 GFW 黑洞(ICMP 和 TCP 都被 drop)
- 服务器关机或网络断开
- 防火墙未放行端口
如何区分: 用 Ping.pe 测试(见下文第二章)
症状2:连接被重置(RST)
表现: 客户端显示 “connection reset by peer”、“EOF”、“broken pipe”
可能原因:
- 端口被 GFW 精准屏蔽(TCP RST 注入)
- 协议特征被识别(如早期 Shadowsocks 的流密码特征)
- 服务器端程序崩溃
如何区分: 换端口测试,如果换端口能连上 → 端口被墙
症状3:速度骤降后断连
表现: 本来速度很快,突然降到几乎为零,然后断开
可能原因:
- GFW 的主动探测(Active Probing)
- 协议握手阶段被识别并限速
- UDP QoS(针对 UDP 协议的限速)
如何区分: 查看日志是否有大量重连
症状4:能连上但无法访问特定网站
表现: 节点状态显示正常,但打不开 Google、YouTube 等网站
可能原因:
- DNS 被污染
- 路由被劫持
- SNI 被检测封锁
- 节点本身被限速(非被墙)
如何区分: 换 DNS、测试不同域名
症状5:间歇性可用
表现: 时好时坏,有时能连有时不能
可能原因:
- GFW 的动态封锁策略(先观察一段时间再封锁)
- 服务器负载过高
- 网络路由不稳定
如何区分: 长时间持续监控
二、诊断法:用 Ping.pe 判断封锁类型
Ping.pe 是判断节点状态的黄金标准。它能从全球多个节点同时测试你的服务器。
2.1 使用方法
- 打开 https://ping.pe
- 输入你的服务器 IP
- 点击 Go
- 观察全球节点的测试结果
2.2 四种典型结果解读
| 结果 | 海外节点 | 国内节点 | 结论 | 应对措施 |
|---|---|---|---|---|
| 场景A | ✅ 通 | ❌ 不通 | IP被黑洞 | 换IP(无解) |
| 场景B | ✅ 通 | ✅ 通 | 正常 | 检查客户端配置 |
| 场景C | ❌ 不通 | ❌ 不通 | 服务器挂了 | 检查服务器状态 |
| 场景D | ✅ 通 | ✅ 通但端口不通 | 端口被墙 | 换端口 |
2.3 Ping.pe + 端口检测结合
Ping.pe 只能测 ICMP(ping),不能测端口。要测端口,用它的姐妹站 port.ping.pe :
- 打开 https://port.ping.pe
- 输入
IP:端口(如1.2.3.4:443) - 观察 TCP 端口连通性
综合判断表:
| ICMP | TCP端口 | 结论 |
|---|---|---|
| 海外通,国内不通 | 海外通,国内不通 | IP 被黑洞 |
| 海外通,国内通 | 海外通,国内不通 | 端口被墙 |
| 全部不通 | 全部不通 | 服务器挂了 |
| 全部通 | 全部通 | 正常,检查客户端 |
三、五种检测方法详解
3.1 方法一:ICMP Ping(最基础)
检测 IP 是否可达:
# 简单 ping
ping 服务器IP -c 10
# 指定间隔和包大小
ping 服务器IP -c 20 -i 0.2 -s 1400结果解读:
| 结果 | 含义 |
|---|---|
| 全部正常,延迟稳定 | IP 正常 |
| 部分丢包 | 网络不稳定或 QoS |
| 全部超时 | IP 可能被黑洞或服务器关机 |
| 海外通但国内不通 | IP 被 GFW 黑洞 |
局限: ICMP 可能被单独封锁(只禁 ping 不禁 TCP),所以只能做初步判断。
3.2 方法二:TCP 连接测试(最常用)
检测 TCP 端口是否开放:
# telnet 测试
telnet 服务器IP 端口
# nc 测试(更推荐)
nc -vz 服务器IP 端口
# tcping(支持测延迟)
tcping 服务器IP 端口
# curl 测试(HTTP/HTTPS)
curl -v -m 5 http://服务器IP:端口
curl -v -m 5 --insecure https://服务器IP:端口结果解读:
| 结果 | 含义 |
|---|---|
Connected / succeeded | 端口开放 |
Connection refused | 端口未监听 |
Connection timed out | 端口被墙或防火墙拦截 |
Connection reset | 端口被 RST 注入封锁 |
3.3 方法三:UDP 连接测试(针对 UDP 协议)
TUIC、Hysteria2 等基于 UDP 的协议需要测 UDP:
# nc UDP 测试
nc -vuz 服务器IP 端口
# nmap UDP 扫描
nmap -sU -p 端口 服务器IP
# 使用特定协议测试(如 TUIC)
# 通过客户端日志判断 UDP 连通性注意: UDP 是无连接的,测试结果不如 TCP 准确。
nc -uz只是检查端口是否有响应,不代表协议本身能通。
3.4 方法四:Traceroute 路由追踪
追踪数据包路径,定位问题出现在哪一跳:
# Linux/macOS
traceroute 服务器IP
# Windows
tracert 服务器IP
# 更详细的 mtr(推荐)
mtr --report --report-cycles 10 服务器IP结果解读:
| 结果 | 含义 |
|---|---|
| 最后一跳正常 | 路由正常 |
| 中间某跳开始超时 | 问题在该跳之后 |
| 国内出口后全部超时 | 可能 GFW 介入 |
| 国外段超时 | 国际线路问题 |
3.5 方法五:协议级测试(最精准)
前面四种都是网络层测试,最精准的是直接用代理客户端测试:
# 用 curl 通过代理测试
https_proxy=http://127.0.0.1:7890 curl -I https://www.google.com
# 测试延迟和下载速度
https_proxy=http://127.0.0.1:7890 curl -o /dev/null -w "%{time_total}" https://speed.cloudflare.com/__down?bytes=100000000
# 用代理链测试节点是否正常工作
# 先连上代理,然后访问 https://ip.sb 看出口 IP 是否正确如果以上测试都通过,说明节点本身是健康的。 如果客户端显示连不上,问题在客户端配置。
四、自动化:节点健康检测脚本
手动检测太麻烦?写个脚本自动监控。
4.1 基础版 Bash 脚本
#!/bin/bash
# 配置
SERVER_IP="你的服务器IP"
SERVER_PORT="你的端口"
CHECK_INTERVAL=300 # 5分钟检查一次
LOG_FILE="/var/log/node-check.log"
TELEGRAM_BOT_TOKEN="你的Bot Token"
TELEGRAM_CHAT_ID="你的Chat ID"
# 发送通知
send_notification() {
local message="$1"
curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d "chat_id=${TELEGRAM_CHAT_ID}" \
-d "text=${message}" > /dev/null
echo "$(date '+%Y-%m-%d %H:%M:%S') [通知] $message" >> "$LOG_FILE"
}
# 检查 TCP 端口
check_tcp() {
timeout 5 bash -c "cat < /dev/null > /dev/tcp/${SERVER_IP}/${SERVER_PORT}"
return $?
}
# 检查 ICMP
check_icmp() {
ping -c 3 -W 2 "$SERVER_IP" > /dev/null 2>&1
return $?
}
# 主检查逻辑
main() {
echo "$(date '+%Y-%m-%d %H:%M:%S') 开始检查节点 ${SERVER_IP}:${SERVER_PORT}" >> "$LOG_FILE"
# TCP 检测
if check_tcp; then
echo "$(date '+%Y-%m-%d %H:%M:%S') [正常] TCP 端口连通" >> "$LOG_FILE"
TCP_STATUS="正常"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') [异常] TCP 端口不通" >> "$LOG_FILE"
TCP_STATUS="异常"
fi
# ICMP 检测
if check_icmp; then
echo "$(date '+%Y-%m-%d %H:%M:%S') [正常] ICMP Ping 正常" >> "$LOG_FILE"
ICMP_STATUS="正常"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') [异常] ICMP Ping 不通" >> "$LOG_FILE"
ICMP_STATUS="异常"
fi
# 综合判断
if [ "$TCP_STATUS" = "异常" ] && [ "$ICMP_STATUS" = "异常" ]; then
send_notification "🚨 节点异常\nIP: ${SERVER_IP}\n端口: ${SERVER_PORT}\nICMP: 不通\nTCP: 不通\n可能原因: 服务器宕机或 IP 被黑洞"
elif [ "$TCP_STATUS" = "异常" ] && [ "$ICMP_STATUS" = "正常" ]; then
send_notification "⚠️ 节点端口异常\nIP: ${SERVER_IP}\n端口: ${SERVER_PORT}\nICMP: 正常\nTCP: 不通\n可能原因: 端口被墙或服务未运行"
fi
}
# 持续监控
while true; do
main
sleep "$CHECK_INTERVAL"
done4.2 Python 进阶版(支持多节点)
#!/usr/bin/env python3
import socket
import subprocess
import time
import json
from datetime import datetime
class NodeChecker:
def __init__(self, config_file="nodes.json"):
with open(config_file) as f:
self.nodes = json.load(f)
self.results = {}
def check_tcp(self, ip, port, timeout=5):
"""检测 TCP 端口"""
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
result = sock.connect_ex((ip, port))
sock.close()
return result == 0
except Exception:
return False
def check_icmp(self, ip, count=3):
"""检测 ICMP"""
try:
result = subprocess.run(
['ping', '-c', str(count), '-W', '2', ip],
capture_output=True, timeout=10
)
return result.returncode == 0
except Exception:
return False
def check_http(self, ip, port, use_https=False, timeout=5):
"""检测 HTTP/HTTPS 可达性"""
import urllib.request
protocol = "https" if use_https else "http"
url = f"{protocol}://{ip}:{port}"
try:
req = urllib.request.Request(url, method='HEAD')
req.add_header('User-Agent', 'NodeChecker/1.0')
response = urllib.request.urlopen(req, timeout=timeout)
return True, response.getcode()
except Exception as e:
return False, str(e)
def diagnose(self, node):
"""综合诊断"""
ip = node['ip']
port = node['port']
name = node['name']
icmp_ok = self.check_icmp(ip)
tcp_ok = self.check_tcp(ip, port)
# 判断状态
if icmp_ok and tcp_ok:
status = "正常"
reason = "节点健康"
elif not icmp_ok and not tcp_ok:
status = "异常"
reason = "IP可能被黑洞或服务器宕机"
elif icmp_ok and not tcp_ok:
status = "异常"
reason = "端口被墙或服务未运行"
else:
status = "可疑"
reason = "ICMP不通但TCP通,可能禁ping"
return {
'name': name,
'ip': ip,
'port': port,
'status': status,
'icmp': '通' if icmp_ok else '不通',
'tcp': '通' if tcp_ok else '不通',
'reason': reason,
'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
def check_all(self):
"""检查所有节点"""
print(f"{'='*60}")
print(f"节点健康检查 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'='*60}")
for node in self.nodes:
result = self.diagnose(node)
self.results[node['name']] = result
icon = "✅" if result['status'] == "正常" else "❌"
print(f"\n{icon} {result['name']}")
print(f" IP: {result['ip']}:{result['port']}")
print(f" 状态: {result['status']}")
print(f" ICMP: {result['icmp']} | TCP: {result['tcp']}")
print(f" 原因: {result['reason']}")
# 统计
total = len(self.results)
normal = sum(1 for r in self.results.values() if r['status'] == "正常")
print(f"\n{'='*60}")
print(f"总计: {total} 个节点 | 正常: {normal} | 异常: {total - normal}")
print(f"{'='*60}")
# 配置文件 nodes.json 示例:
# [
# {"name": "东京01", "ip": "1.2.3.4", "port": 443},
# {"name": "新加坡01", "ip": "5.6.7.8", "port": 8443}
# ]
if __name__ == "__main__":
checker = NodeChecker()
checker.check_all()4.3 配置文件 nodes.json
[
{
"name": "🇯🇵 东京 IEPL",
"ip": "1.2.3.4",
"port": 443
},
{
"name": "🇸🇬 新加坡 BGP",
"ip": "5.6.7.8",
"port": 8443
},
{
"name": "🇺🇸 洛杉矶 CN2",
"ip": "9.10.11.12",
"port": 2087
}
]4.4 加入定时任务
# 每 10 分钟检查一次
crontab -e
# 添加:
*/10 * * * * /usr/bin/python3 /opt/node-checker/check.py >> /var/log/node-check.log 2>&1五、节点复活方案
5.1 端口被墙 → 换端口
最简单的方案:
# 修改服务端配置,换一个高位端口(如 40000-60000 之间)
# 然后重启服务
systemctl restart sing-box
# 客户端同步更新端口端口选择建议:
| 端口范围 | 特点 | 被墙概率 |
|---|---|---|
| 443 | HTTPS 标准端口 | 中等(如果IP没被墙) |
| 80 | HTTP 标准端口 | 中等 |
| 8080 | 替代 HTTP | 较高 |
| 8443 | 替代 HTTPS | 较低 |
| 40000-60000 | 高位随机端口 | 最低 |
建议: 自建节点尽量用 40000+ 的随机高位端口,被墙概率最低。
5.2 IP 被黑洞 → 换 IP
如果 IP 被黑洞,只能换 IP:
- VPS 用户: 大多数云服务商支持免费换 IP(如 Vultr 销毁重建)
- 专线用户: 联系服务商更换 IP
- 预防: 使用 CDN 前置(如 Cloudflare)隐藏真实 IP
5.3 协议被识别 → 换协议
如果协议特征被识别:
| 被识别协议 | 建议切换到 |
|---|---|
| Shadowsocks(旧版) | VLESS+Reality / TUIC |
| VMess(无 TLS) | VLESS+XTLS / Hysteria2 |
| Trojan(默认配置) | Trojan+TLS(加强配置) |
| 简单 TLS | REALITY / XTLS |
5.4 使用 CDN 隐藏真实 IP
Cloudflare 等 CDN 可以隐藏服务器真实 IP:
- 域名接入 Cloudflare
- 只暴露 CDN 的 IP
- 真实服务器 IP 永不暴露
注意: 只有支持 WebSocket/gRPC 的协议才能走 CDN(如 VLESS+WS+CDN)。
六、总结
6.1 快速诊断流程图
节点连不上?
│
├─→ Ping.pe 测试 IP
│ │
│ ├─→ 国内外都不通 → 服务器挂了
│ │
│ └─→ 国内不通,海外通 → IP 被黑洞
│
├─→ port.ping.pe 测试端口
│ │
│ ├─→ 国内外都不通 → 服务没运行
│ │
│ └─→ 国内不通,海外通 → 端口被墙
│
└─→ 客户端日志分析
│
├─→ timeout → 网络层问题
│
├─→ reset → 端口/协议被识别
│
└─→ 其他错误 → 配置问题6.2 检测工具速查表
| 工具 | 检测类型 | 适用场景 |
|---|---|---|
| Ping.pe | ICMP | 判断 IP 是否被黑洞 |
| port.ping.pe | TCP | 判断端口是否被墙 |
| tcping | TCP + 延迟 | 测试 TCP 连通性和延迟 |
| mtr | 路由追踪 | 定位网络问题节点 |
| curl + 代理 | 协议级 | 测试代理是否正常工作 |
| 自定义脚本 | 综合 | 自动化监控 |
6.3 预防被墙的建议
- 使用 40000+ 高位随机端口
- 使用抗检测协议(VLESS+Reality / TUIC / Hysteria2)
- 配合 CDN 隐藏真实 IP
- 定期更换端口(如每月一次)
- 监控节点状态,发现问题及时切换
【相关推荐】
- 端口检测完全指南 - 本地与公网端口排查
- Linux 防火墙放行教程 - 服务端防火墙配置
- TUIC 协议搭建教程 - 抗检测协议搭建
- 3x-ui 面板管理 - 可视化节点管理
节点被墙不可怕,可怕的是不知道怎么判断、不知道怎么解决。掌握这套检测方法,你就能在问题出现的第一时间定位原因,而不是盲目地切来切去。🚀
