Files
16gagent/game-accelerator-tech-plan/05-客户端开发方案.md
T

721 lines
63 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第五部分:客户端开发方案
## 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.550%以下不扣分) │
│ - 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审核相对宽松 │ │
│ │ │ │
│ │ 适用游戏: │ │
│ │ - 手游(全品类) │ │
│ │ - 云游戏 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
```