721 lines
63 KiB
Markdown
721 lines
63 KiB
Markdown
# 第五部分:客户端开发方案
|
||
|
||
## 5.1 Windows客户端(优先)
|
||
|
||
### 5.1.1 网络驱动方案对比
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||
│ Windows 网络驱动方案对比 │
|
||
├──────────────┬──────────────┬──────────────┬──────────────┬─────────────────┤
|
||
│ 方案 │ WFP │ WinDivert │ TUN/TAP │ NDIS Filter │
|
||
├──────────────┼──────────────┼──────────────┼──────────────┼─────────────────┤
|
||
│ 层级 │ 内核态 │ 用户态 │ 用户态 │ 内核态 │
|
||
│ 兼容性 │ Win7+ │ Win7+ │ 全平台 │ Win7+ │
|
||
│ 性能 │ ★★★★★ │ ★★★★ │ ★★★ │ ★★★★ │
|
||
│ 稳定性 │ ★★★★★ │ ★★★★ │ ★★★ │ ★★★ │
|
||
│ 进程过滤 │ ✓ │ ✓ │ ✗ │ ✗ │
|
||
│ IP/端口过滤 │ ✓ │ ✓ │ ✓ │ ✓ │
|
||
│ 协议过滤 │ ✓ │ ✓ │ ✗ │ ✓ │
|
||
│ 驱动签名 │ 需要 │ 需要 │ 需要 │ 需要 │
|
||
│ 开发难度 │ 高 │ 中 │ 低 │ 高 │
|
||
│ 微软官方 │ ✓ │ ✗(第三方) │ ✗ │ ✓ │
|
||
│ 蓝屏风险 │ 低 │ 低 │ 无 │ 中 │
|
||
├──────────────┼──────────────┼──────────────┼──────────────┼─────────────────┤
|
||
│ 推荐度 │ ★★★★★ │ ★★★★ │ ★★★ │ ★★★ │
|
||
├──────────────┴──────────────┴──────────────┴──────────────┴─────────────────┤
|
||
│ │
|
||
│ ★ 推荐方案:WFP (Windows Filtering Platform) │
|
||
│ │
|
||
│ 理由: │
|
||
│ 1. 微软官方支持,Win7-Win11全系列 │
|
||
│ 2. 内核态过滤,性能最优 │
|
||
│ 3. 支持按进程PID过滤(核心需求) │
|
||
│ 4. 支持ALE层(应用层强制)和传输层过滤 │
|
||
│ 5. 稳定性最高,蓝屏风险最低 │
|
||
│ 6. 支持Win10/11的Modern Standby │
|
||
│ │
|
||
│ 备选方案:WinDivert(开发阶段快速原型验证) │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 5.1.2 WFP驱动架构详细设计
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ WFP Callout Driver 架构 │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ ┌────────────────────────────────────────────────────────┐ │
|
||
│ │ 用户态 (Ring 3) │ │
|
||
│ │ ┌──────────────────────────────────────────────────┐ │ │
|
||
│ │ │ Accelerator Client Process │ │ │
|
||
│ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │
|
||
│ │ │ │ 流量管理 │ │ 隧道引擎 │ │ 策略引擎 │ │ │ │
|
||
│ │ │ │ Engine │ │ Tunnel │ │ Policy │ │ │ │
|
||
│ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │
|
||
│ │ │ └──────────────┴──────────────┘ │ │ │
|
||
│ │ │ │ │ │ │
|
||
│ │ │ DeviceIoControl │ │ │
|
||
│ │ │ │ │ │ │
|
||
│ │ │ ┌──────────────────────────────────────────┐ │ │ │
|
||
│ │ │ │ WFP Control Interface │ │ │ │
|
||
│ │ │ │ - 添加/删除过滤规则 │ │ │ │
|
||
│ │ │ │ - 获取流量统计 │ │ │ │
|
||
│ │ │ │ - 配置驱动参数 │ │ │ │
|
||
│ │ │ └──────────────────────────────────────────┘ │ │ │
|
||
│ │ └──────────────────────────────────────────────────┘ │ │
|
||
│ └────────────────────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ┌────────────────────────────────────────────────────────┐ │
|
||
│ │ 内核态 (Ring 0) │ │
|
||
│ │ ┌──────────────────────────────────────────────────┐ │ │
|
||
│ │ │ WFP Callout Driver (.sys) │ │ │
|
||
│ │ │ │ │ │
|
||
│ │ │ ┌────────────────────────────────────────────┐ │ │ │
|
||
│ │ │ │ ALE Layer (Application Layer Enforcement) │ │ │ │
|
||
│ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │
|
||
│ │ │ │ │ ALE_AUTH_CONNECT_V4 │ │ │ │ │
|
||
│ │ │ │ │ - 拦截出站连接请求 │ │ │ │ │
|
||
│ │ │ │ │ - 获取进程PID、目标IP、端口 │ │ │ │ │
|
||
│ │ │ │ │ - 查询策略:是否需要加速 │ │ │ │ │
|
||
│ │ │ │ │ - 决定:放行(FWP_ACTION_PERMIT) │ │ │ │ │
|
||
│ │ │ │ │ 拦截(FWP_ACTION_BLOCK) │ │ │ │ │
|
||
│ │ │ │ │ 重定向(修改目标地址) │ │ │ │ │
|
||
│ │ │ │ └──────────────────────────────────────┘ │ │ │ │
|
||
│ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │
|
||
│ │ │ │ │ ALE_AUTH_RECV_ACCEPT_V4 │ │ │ │ │
|
||
│ │ │ │ │ - 拦截入站连接请求 │ │ │ │ │
|
||
│ │ │ │ │ - 用于P2P游戏场景 │ │ │ │ │
|
||
│ │ │ │ └──────────────────────────────────────┘ │ │ │ │
|
||
│ │ │ └────────────────────────────────────────────┘ │ │ │
|
||
│ │ │ │ │ │
|
||
│ │ │ ┌────────────────────────────────────────────┐ │ │ │
|
||
│ │ │ │ Transport Layer │ │ │ │
|
||
│ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │
|
||
│ │ │ │ │ OUTBOUND_TRANSPORT_V4 │ │ │ │ │
|
||
│ │ │ │ │ - 出站数据包级别过滤 │ │ │ │ │
|
||
│ │ │ │ │ - 修改目标地址(重定向到隧道) │ │ │ │ │
|
||
│ │ │ │ │ - 添加标记用于回程识别 │ │ │ │ │
|
||
│ │ │ │ └──────────────────────────────────────┘ │ │ │ │
|
||
│ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │
|
||
│ │ │ │ │ INBOUND_TRANSPORT_V4 │ │ │ │ │
|
||
│ │ │ │ │ - 入站数据包过滤 │ │ │ │ │
|
||
│ │ │ │ │ - 识别隧道回程包并还原 │ │ │ │ │
|
||
│ │ │ │ └──────────────────────────────────────┘ │ │ │ │
|
||
│ │ │ └────────────────────────────────────────────┘ │ │ │
|
||
│ │ │ │ │ │
|
||
│ │ │ ┌────────────────────────────────────────────┐ │ │ │
|
||
│ │ │ │ Network Layer │ │ │ │
|
||
│ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │
|
||
│ │ │ │ │ IP_PACKET_V4 │ │ │ │ │
|
||
│ │ │ │ │ - 数据包级别统计 │ │ │ │ │
|
||
│ │ │ │ │ - 流量计数 │ │ │ │ │
|
||
│ │ │ │ └──────────────────────────────────────┘ │ │ │ │
|
||
│ │ │ └────────────────────────────────────────────┘ │ │ │
|
||
│ │ │ │ │ │
|
||
│ │ │ ┌────────────────────────────────────────────┐ │ │ │
|
||
│ │ │ │ 数据结构 │ │ │ │
|
||
│ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │
|
||
│ │ │ │ │ FilterRule { │ │ │ │ │
|
||
│ │ │ │ │ ProcessId uint32 │ │ │ │ │
|
||
│ │ │ │ │ DestIP net.IP │ │ │ │ │
|
||
│ │ │ │ │ DestPort uint16 │ │ │ │ │
|
||
│ │ │ │ │ Protocol uint8 // TCP/UDP │ │ │ │ │
|
||
│ │ │ │ │ Action uint8 // Permit/Block │ │ │ │ │
|
||
│ │ │ │ │ TunnelType uint8 // UDP/QUIC │ │ │ │ │
|
||
│ │ │ │ │ NodeID string // 目标节点 │ │ │ │ │
|
||
│ │ │ │ │ } │ │ │ │ │
|
||
│ │ │ │ └──────────────────────────────────────┘ │ │ │ │
|
||
│ │ │ └────────────────────────────────────────────┘ │ │ │
|
||
│ │ └──────────────────────────────────────────────────┘ │ │
|
||
│ └────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 5.1.3 游戏流量识别
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 游戏流量识别方案 │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 识别维度: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 1. 进程识别(最可靠) │ │
|
||
│ │ - 获取进程PID │ │
|
||
│ │ - 查询进程路径 │ │
|
||
│ │ - 匹配游戏配置库 │ │
|
||
│ │ 示例: │ │
|
||
│ │ PID=1234 → C:\Genshin Impact\GenshinImpact.exe │ │
|
||
│ │ → 匹配为"原神" │ │
|
||
│ │ │ │
|
||
│ │ 2. IP识别(精准) │ │
|
||
│ │ - 维护游戏服务器IP列表 │ │
|
||
│ │ - 查询目标IP是否属于某游戏 │ │
|
||
│ │ 示例: │ │
|
||
│ │ 目标IP=47.245.x.x → 属于"原神亚服" │ │
|
||
│ │ │ │
|
||
│ │ 3. 域名识别(灵活) │ │
|
||
│ │ - DNS请求拦截 │ │
|
||
│ │ - 查询域名是否属于某游戏 │ │
|
||
│ │ 示例: │ │
|
||
│ │ 域名=*.mihoyo.com → 属于"原神" │ │
|
||
│ │ │ │
|
||
│ │ 4. 端口识别(辅助) │ │
|
||
│ │ - 特定端口通常对应特定游戏 │ │
|
||
│ │ 示例: │ │
|
||
│ │ 端口27015-27030 → 可能是Steam游戏 │ │
|
||
│ │ │ │
|
||
│ │ 5. 协议特征识别(深度包检测) │ │
|
||
│ │ - 分析数据包载荷特征 │ │
|
||
│ │ - 匹配已知游戏协议 │ │
|
||
│ │ 示例: │ │
|
||
│ │ 前4字节=0x01020304 → "某某游戏"协议头 │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 识别优先级:进程 > IP > 域名 > 端口 > 协议特征 │
|
||
│ │
|
||
│ 游戏配置数据库结构: │
|
||
│ │
|
||
│ // GameConfig 游戏配置 │
|
||
│ { │
|
||
│ "game_id": "genshin_impact", │
|
||
│ "name": "原神", │
|
||
│ "icon": "genshin.png", │
|
||
│ "category": "mmorpg", │
|
||
│ "process_names": [ │
|
||
│ "GenshinImpact.exe", │
|
||
│ "YuanShen.exe" │
|
||
│ ], │
|
||
│ "install_paths": [ │
|
||
│ "C:\\Program Files\\Genshin Impact\\", │
|
||
│ "D:\\Games\\Genshin Impact\\" │
|
||
│ ], │
|
||
│ "servers": [ │
|
||
│ { │
|
||
│ "name": "亚服", │
|
||
│ "region": "asia", │
|
||
│ "ip_ranges": [ │
|
||
│ "47.245.0.0/16", │
|
||
│ "8.219.0.0/16" │
|
||
│ ], │
|
||
│ "domains": [ │
|
||
│ "*.mihoyo.com", │
|
||
│ "*.hoyoverse.com" │
|
||
│ ], │
|
||
│ "ports": [443, 80, 22102], │
|
||
│ "protocol": "tcp+udp" │
|
||
│ }, │
|
||
│ { │
|
||
│ "name": "美服", │
|
||
│ "region": "america", │
|
||
│ "ip_ranges": ["47.252.0.0/16"], │
|
||
│ "ports": [443, 80, 22102], │
|
||
│ "protocol": "tcp+udp" │
|
||
│ } │
|
||
│ ], │
|
||
│ "capture_mode": "process_ip", │
|
||
│ "tunnel_mode": "udp_relay", │
|
||
│ "priority": "high", │
|
||
│ "qos_class": "realtime" │
|
||
│ } │
|
||
│ │
|
||
│ // ServerConfig 服务器配置 │
|
||
│ { │
|
||
│ "server_id": "asia_01", │
|
||
│ "game_id": "genshin_impact", │
|
||
│ "name": "亚服-东京", │
|
||
│ "ip": "47.245.1.1", │
|
||
│ "port": 22102, │
|
||
│ "protocol": "udp", │
|
||
│ "location": {"lat": 35.6762, "lng": 139.6503}, │
|
||
│ "isp": "softbank" │
|
||
│ } │
|
||
│ │
|
||
│ // RouteConfig 路由配置 │
|
||
│ { │
|
||
│ "route_id": "genshin_asia_route_01", │
|
||
│ "game_id": "genshin_impact", │
|
||
│ "source_region": "china_north", │
|
||
│ "dest_region": "japan", │
|
||
│ "access_node": "cn-bj-01", │
|
||
│ "relay_nodes": ["cn-sh-01", "hk-01"], │
|
||
│ "exit_node": "jp-tokyo-01", │
|
||
│ "protocol": "quic", │
|
||
│ "fec_level": 2, │
|
||
│ "priority": "high" │
|
||
│ } │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 5.2 自动选路系统
|
||
|
||
### 5.2.1 测速算法
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 测速算法详细设计 │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 1. 延迟测试(RTT) │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 算法:UDP Ping │ │
|
||
│ │ │ │
|
||
│ │ 输入:目标节点IP、端口 │ │
|
||
│ │ 输出:RTT(毫秒) │ │
|
||
│ │ │ │
|
||
│ │ 步骤: │ │
|
||
│ │ 1. 发送UDP探测包(带时间戳) │ │
|
||
│ │ 2. 等待回复 │ │
|
||
│ │ 3. 计算 RTT = 收到时间 - 发送时间 │ │
|
||
│ │ 4. 连续发送10个包,间隔100ms │ │
|
||
│ │ 5. 去除最高和最低值,取平均 │ │
|
||
│ │ │ │
|
||
│ │ 伪代码: │ │
|
||
│ │ func measureRTT(node string) float64 { │ │
|
||
│ │ var rtts []float64 │ │
|
||
│ │ for i := 0; i < 10; i++ { │ │
|
||
│ │ start := time.Now() │ │
|
||
│ │ sendUDPPing(node) │ │
|
||
│ │ waitPong() │ │
|
||
│ │ rtt := time.Since(start).Milliseconds() │ │
|
||
│ │ rtts = append(rtts, float64(rtt)) │ │
|
||
│ │ time.Sleep(100 * time.Millisecond) │ │
|
||
│ │ } │ │
|
||
│ │ sort.Float64s(rtts) │ │
|
||
│ │ // 去除最高最低,取平均 │ │
|
||
│ │ return average(rtts[1:9]) │ │
|
||
│ │ } │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 2. 丢包率测试 │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 算法:统计法 │ │
|
||
│ │ │ │
|
||
│ │ 步骤: │ │
|
||
│ │ 1. 发送20个UDP包,间隔50ms │ │
|
||
│ │ 2. 等待2秒收集回复 │ │
|
||
│ │ 3. 统计收到的回复数 │ │
|
||
│ │ 4. 丢包率 = (20 - 回复数) / 20 │ │
|
||
│ │ 5. 重复3轮,取平均 │ │
|
||
│ │ │ │
|
||
│ │ 伪代码: │ │
|
||
│ │ func measureLoss(node string) float64 { │ │
|
||
│ │ var losses []float64 │ │
|
||
│ │ for round := 0; round < 3; round++ { │ │
|
||
│ │ sent := 20 │ │
|
||
│ │ received := 0 │ │
|
||
│ │ for i := 0; i < sent; i++ { │ │
|
||
│ │ sendUDPPing(node) │ │
|
||
│ │ time.Sleep(50 * time.Millisecond) │ │
|
||
│ │ } │ │
|
||
│ │ // 收集回复 │ │
|
||
│ │ timeout := time.After(2 * time.Second) │ │
|
||
│ │ for { │ │
|
||
│ │ select { │ │
|
||
│ │ case <-pongChan: │ │
|
||
│ │ received++ │ │
|
||
│ │ case <-timeout: │ │
|
||
│ │ goto done │ │
|
||
│ │ } │ │
|
||
│ │ } │ │
|
||
│ │ done: │ │
|
||
│ │ loss := float64(sent-received) / float64(sent) │ │
|
||
│ │ losses = append(losses, loss) │ │
|
||
│ │ } │ │
|
||
│ │ return average(losses) │ │
|
||
│ │ } │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 3. 抖动测试(Jitter) │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 算法:RTT标准差 │ │
|
||
│ │ │ │
|
||
│ │ 公式:Jitter = sqrt(Σ(RTTi - RTT_avg)² / N) │ │
|
||
│ │ │ │
|
||
│ │ 步骤: │ │
|
||
│ │ 1. 使用RTT测试的10个样本 │ │
|
||
│ │ 2. 计算平均值 │ │
|
||
│ │ 3. 计算每个样本与平均值的差的平方和 │ │
|
||
│ │ 4. 开方得到标准差 │ │
|
||
│ │ │ │
|
||
│ │ 伪代码: │ │
|
||
│ │ func measureJitter(rtts []float64) float64 { │ │
|
||
│ │ avg := average(rtts) │ │
|
||
│ │ var sum float64 │ │
|
||
│ │ for _, rtt := range rtts { │ │
|
||
│ │ diff := rtt - avg │ │
|
||
│ │ sum += diff * diff │ │
|
||
│ │ } │ │
|
||
│ │ return math.Sqrt(sum / float64(len(rtts))) │ │
|
||
│ │ } │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 4. 带宽测试 │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 算法:递增探测法 │ │
|
||
│ │ │ │
|
||
│ │ 步骤: │ │
|
||
│ │ 1. 发送递增大小的数据包:1KB, 4KB, 16KB, 64KB, 256KB │ │
|
||
│ │ 2. 测量每个大小的传输时间 │ │
|
||
│ │ 3. 计算吞吐量 = 大小 / 时间 │ │
|
||
│ │ 4. 取最大吞吐量作为带宽估计 │ │
|
||
│ │ │ │
|
||
│ │ 伪代码: │ │
|
||
│ │ func measureBandwidth(node string) float64 { │ │
|
||
│ │ sizes := []int{1024, 4096, 16384, 65536, 262144} │ │
|
||
│ │ var maxBw float64 │ │
|
||
│ │ for _, size := range sizes { │ │
|
||
│ │ data := make([]byte, size) │ │
|
||
│ │ start := time.Now() │ │
|
||
│ │ sendData(node, data) │ │
|
||
│ │ waitACK() │ │
|
||
│ │ elapsed := time.Since(start).Seconds() │ │
|
||
│ │ bw := float64(size) * 8 / elapsed / 1e6 │ │
|
||
│ │ if bw > maxBw { │ │
|
||
│ │ maxBw = bw │ │
|
||
│ │ } │ │
|
||
│ │ } │ │
|
||
│ │ return maxBw // Mbps │ │
|
||
│ │ } │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 5.2.2 评分算法
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 节点评分算法 │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 综合评分公式: │
|
||
│ │
|
||
│ Score(i) = 100 │
|
||
│ - RTT_penalty(i) │
|
||
│ - Loss_penalty(i) │
|
||
│ - Jitter_penalty(i) │
|
||
│ - Load_penalty(i) │
|
||
│ + Bonus(i) │
|
||
│ │
|
||
│ 各项扣分计算: │
|
||
│ │
|
||
│ 1. RTT扣分: │
|
||
│ RTT_penalty = max(0, (RTT - RTT_base) × RTT_factor) │
|
||
│ 其中: │
|
||
│ - RTT_base = 30ms(基准延迟) │
|
||
│ - RTT_factor = 0.5(每ms扣0.5分) │
|
||
│ - 最大扣分:50分 │
|
||
│ │
|
||
│ 2. 丢包扣分: │
|
||
│ Loss_penalty = Loss_rate × Loss_factor │
|
||
│ 其中: │
|
||
│ - Loss_rate = 丢包率(0-1) │
|
||
│ - Loss_factor = 200(每1%丢包扣2分) │
|
||
│ - 最大扣分:50分 │
|
||
│ │
|
||
│ 3. 抖动扣分: │
|
||
│ Jitter_penalty = Jitter × Jitter_factor │
|
||
│ 其中: │
|
||
│ - Jitter = 抖动值(ms) │
|
||
│ - Jitter_factor = 2(每ms抖动扣2分) │
|
||
│ - 最大扣分:30分 │
|
||
│ │
|
||
│ 4. 负载扣分: │
|
||
│ Load_penalty = (Load_rate - Load_threshold) × Load_factor │
|
||
│ 其中: │
|
||
│ - Load_rate = 负载率(0-1) │
|
||
│ - Load_threshold = 0.5(50%以下不扣分) │
|
||
│ - Load_factor = 40 │
|
||
│ - 最大扣分:20分 │
|
||
│ │
|
||
│ 5. 加分项: │
|
||
│ - 专线节点:+10分 │
|
||
│ - BGP多线:+5分 │
|
||
│ - 同ISP:+5分 │
|
||
│ - 同城市:+10分 │
|
||
│ │
|
||
│ 评分等级: │
|
||
│ ┌──────────┬──────────┬──────────────────────────┐ │
|
||
│ │ 分数 │ 等级 │ 说明 │ │
|
||
│ ├──────────┼──────────┼──────────────────────────┤ │
|
||
│ │ 90-100 │ 极佳 │ 最优选择,绿色显示 │ │
|
||
│ │ 70-89 │ 良好 │ 推荐选择,黄色显示 │ │
|
||
│ │ 50-69 │ 一般 │ 可用,橙色显示 │ │
|
||
│ │ <50 │ 较差 │ 不推荐,红色显示 │ │
|
||
│ └──────────┴──────────┴──────────────────────────┘ │
|
||
│ │
|
||
│ 伪代码实现: │
|
||
│ │
|
||
│ func calculateScore(node *Node, user *User) float64 { │
|
||
│ score := 100.0 │
|
||
│ │
|
||
│ // RTT扣分 │
|
||
│ rttPenalty := math.Max(0, (node.RTT-30)*0.5) │
|
||
│ rttPenalty = math.Min(rttPenalty, 50) │
|
||
│ score -= rttPenalty │
|
||
│ │
|
||
│ // 丢包扣分 │
|
||
│ lossPenalty := node.LossRate * 200 │
|
||
│ lossPenalty = math.Min(lossPenalty, 50) │
|
||
│ score -= lossPenalty │
|
||
│ │
|
||
│ // 抖动扣分 │
|
||
│ jitterPenalty := node.Jitter * 2 │
|
||
│ jitterPenalty = math.Min(jitterPenalty, 30) │
|
||
│ score -= jitterPenalty │
|
||
│ │
|
||
│ // 负载扣分 │
|
||
│ if node.LoadRate > 0.5 { │
|
||
│ loadPenalty := (node.LoadRate - 0.5) * 40 │
|
||
│ score -= loadPenalty │
|
||
│ } │
|
||
│ │
|
||
│ // 加分项 │
|
||
│ if node.IsDedicatedLine { score += 10 } │
|
||
│ if node.IsBGP { score += 5 } │
|
||
│ if node.ISP == user.ISP { score += 5 } │
|
||
│ if node.City == user.City { score += 10 } │
|
||
│ │
|
||
│ return math.Max(0, math.Min(100, score)) │
|
||
│ } │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 5.2.3 节点选择算法
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 节点选择算法 │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 输入: │
|
||
│ - 用户信息:地理位置、ISP、当前网络状况 │
|
||
│ - 游戏信息:目标服务器地址、协议类型 │
|
||
│ - 节点列表:所有可用节点及其状态 │
|
||
│ │
|
||
│ 输出: │
|
||
│ - 最优节点(主节点) │
|
||
│ - 备用节点列表(2-3个) │
|
||
│ - 推荐路由路径 │
|
||
│ │
|
||
│ 算法流程: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ Step 1: 候选节点筛选 │ │
|
||
│ │ ┌────────────────────────────────────────────────────┐ │ │
|
||
│ │ │ for each node in all_nodes: │ │ │
|
||
│ │ │ if node.status != "online": │ │ │
|
||
│ │ │ skip │ │ │
|
||
│ │ │ if node.load_rate > 0.9: │ │ │
|
||
│ │ │ skip │ │ │
|
||
│ │ │ if not node.supports_game(game_id): │ │ │
|
||
│ │ │ skip │ │ │
|
||
│ │ │ candidates.add(node) │ │ │
|
||
│ │ └────────────────────────────────────────────────────┘ │ │
|
||
│ │ │ │
|
||
│ │ Step 2: 地理位置匹配 │ │
|
||
│ │ ┌────────────────────────────────────────────────────┐ │ │
|
||
│ │ │ // 优先选择同区域节点 │ │ │
|
||
│ │ │ same_region = filter(candidates, same_region) │ │ │
|
||
│ │ │ if len(same_region) > 0: │ │ │
|
||
│ │ │ candidates = same_region │ │ │
|
||
│ │ │ │ │ │
|
||
│ │ │ // 优先选择同ISP节点 │ │ │
|
||
│ │ │ same_isp = filter(candidates, same_isp) │ │ │
|
||
│ │ │ if len(same_isp) > 0: │ │ │
|
||
│ │ │ candidates = same_isp │ │ │
|
||
│ │ └────────────────────────────────────────────────────┘ │ │
|
||
│ │ │ │
|
||
│ │ Step 3: 质量评分 │ │
|
||
│ │ ┌────────────────────────────────────────────────────┐ │ │
|
||
│ │ │ for each node in candidates: │ │ │
|
||
│ │ │ node.score = calculateScore(node, user) │ │ │
|
||
│ │ │ │ │ │
|
||
│ │ │ // 按评分排序 │ │ │
|
||
│ │ │ candidates.sort_by_score_desc() │ │ │
|
||
│ │ └────────────────────────────────────────────────────┘ │ │
|
||
│ │ │ │
|
||
│ │ Step 4: 选择最优 │ │
|
||
│ │ ┌────────────────────────────────────────────────────┐ │ │
|
||
│ │ │ best_node = candidates[0] │ │ │
|
||
│ │ │ backup_nodes = candidates[1:3] // 取2个备用 │ │ │
|
||
│ │ │ │ │ │
|
||
│ │ │ // 构建路由路径 │ │ │
|
||
│ │ │ route = build_route(user, best_node, game_server) │ │ │
|
||
│ │ └────────────────────────────────────────────────────┘ │ │
|
||
│ │ │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 5.2.4 自动切换算法
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 自动切换算法 │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 切换触发条件(满足任一即触发): │
|
||
│ 1. 当前节点RTT > 最优节点RTT × 1.5 │
|
||
│ 2. 当前节点丢包率 > 5% │
|
||
│ 3. 连续3次探测质量下降 │
|
||
│ 4. 当前节点负载 > 80% │
|
||
│ 5. 当前节点离线 │
|
||
│ 6. 用户手动切换 │
|
||
│ │
|
||
│ 切换决策流程: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ 每隔10秒执行一次检测: │ │
|
||
│ │ │ │
|
||
│ │ func autoSwitchCheck() { │ │
|
||
│ │ // 1. 测试当前节点质量 │ │
|
||
│ │ currentQuality = testNode(currentNode) │ │
|
||
│ │ │ │
|
||
│ │ // 2. 测试备用节点质量 │ │
|
||
│ │ for each backup in backupNodes: │ │
|
||
│ │ backup.quality = testNode(backup) │ │
|
||
│ │ │ │
|
||
│ │ // 3. 找到最优节点 │ │
|
||
│ │ bestBackup = findBest(backupNodes) │ │
|
||
│ │ │ │
|
||
│ │ // 4. 判断是否需要切换 │ │
|
||
│ │ needSwitch := false │ │
|
||
│ │ │ │
|
||
│ │ // 条件1:延迟差异 │ │
|
||
│ │ if currentQuality.RTT > bestBackup.RTT * 1.5 { │ │
|
||
│ │ needSwitch = true │ │
|
||
│ │ } │ │
|
||
│ │ │ │
|
||
│ │ // 条件2:丢包率 │ │
|
||
│ │ if currentQuality.LossRate > 0.05 { │ │
|
||
│ │ needSwitch = true │ │
|
||
│ │ } │ │
|
||
│ │ │ │
|
||
│ │ // 条件3:连续下降 │ │
|
||
│ │ if qualityDeclineCount >= 3 { │ │
|
||
│ │ needSwitch = true │ │
|
||
│ │ qualityDeclineCount = 0 │ │
|
||
│ │ } │ │
|
||
│ │ │ │
|
||
│ │ // 条件4:负载过高 │ │
|
||
│ │ if currentNode.LoadRate > 0.8 { │ │
|
||
│ │ needSwitch = true │ │
|
||
│ │ } │ │
|
||
│ │ │ │
|
||
│ │ // 5. 执行切换 │ │
|
||
│ │ if needSwitch && bestBackup.Score > 60 { │ │
|
||
│ │ switchTo(bestBackup) │ │
|
||
│ │ } │ │
|
||
│ │ } │ │
|
||
│ │ │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 切换执行流程(无缝切换): │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ func switchTo(newNode *Node) { │ │
|
||
│ │ // 1. 预建立新连接 │ │
|
||
│ │ newConn = establishConnection(newNode) │ │
|
||
│ │ │ │
|
||
│ │ // 2. 迁移会话状态 │ │
|
||
│ │ migrateSession(currentSession, newConn) │ │
|
||
│ │ │ │
|
||
│ │ // 3. 切换流量 │ │
|
||
│ │ redirectTraffic(newConn) │ │
|
||
│ │ │ │
|
||
│ │ // 4. 验证新连接 │ │
|
||
│ │ if verifyConnection(newConn) { │ │
|
||
│ │ // 5. 关闭旧连接 │ │
|
||
│ │ closeConnection(oldConn) │ │
|
||
│ │ currentNode = newNode │ │
|
||
│ │ log("Switch success") │ │
|
||
│ │ } else { │ │
|
||
│ │ // 切换失败,回滚 │ │
|
||
│ │ rollback(oldConn) │ │
|
||
│ │ log("Switch failed, rolled back") │ │
|
||
│ │ } │ │
|
||
│ │ } │ │
|
||
│ │ │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 5.3 macOS/iOS/Android客户端
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 跨平台客户端方案 │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ macOS客户端: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 技术栈:Swift + Network Extension (NEPacketTunnelProvider)│ │
|
||
│ │ │ │
|
||
│ │ 流量捕获: │ │
|
||
│ │ - Network Extension (NEPacketTunnelProvider) │ │
|
||
│ │ - 系统级VPN框架,稳定性高 │ │
|
||
│ │ - 支持按App过滤(macOS 11+) │ │
|
||
│ │ │ │
|
||
│ │ 隧道实现: │ │
|
||
│ │ - 用户态UDP隧道 │ │
|
||
│ │ - 或QUIC隧道(quic-go Swift binding) │ │
|
||
│ │ │ │
|
||
│ │ 限制: │ │
|
||
│ │ - 需要App Store审核 │ │
|
||
│ │ - Network Extension有沙箱限制 │ │
|
||
│ │ - 无法实现内核态驱动 │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ iOS客户端: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 技术栈:Swift + Network Extension │ │
|
||
│ │ │ │
|
||
│ │ 流量捕获: │ │
|
||
│ │ - NEPacketTunnelProvider (Packet Tunnel) │ │
|
||
│ │ - 支持按App过滤(iOS 14+) │ │
|
||
│ │ - 系统级VPN框架 │ │
|
||
│ │ │ │
|
||
│ │ 限制: │ │
|
||
│ │ - App Store审核严格(需说明加速器用途) │ │
|
||
│ │ - 沙箱限制更严格 │ │
|
||
│ │ - 后台运行限制 │ │
|
||
│ │ - 无法实现内核态操作 │ │
|
||
│ │ │ │
|
||
│ │ 适用游戏: │ │
|
||
│ │ - 手游(原神、PUBG Mobile等) │ │
|
||
│ │ - 云游戏 │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ Android客户端: │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 技术栈:Kotlin + VpnService │ │
|
||
│ │ │ │
|
||
│ │ 流量捕获: │ │
|
||
│ │ - VpnService (系统级VPN) │ │
|
||
│ │ - 支持TUN设备 │ │
|
||
│ │ - 可获取进程UID │ │
|
||
│ │ │ │
|
||
│ │ 优势: │ │
|
||
│ │ - 开发灵活度最高 │ │
|
||
│ │ - 可获取进程信息 │ │
|
||
│ │ - 支持自定义协议 │ │
|
||
│ │ - Google Play审核相对宽松 │ │
|
||
│ │ │ │
|
||
│ │ 适用游戏: │ │
|
||
│ │ - 手游(全品类) │ │
|
||
│ │ - 云游戏 │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|