这是用户在 2025-7-23 19:41 为 https://github.com/copilot/c/f3ddc6a8-1c74-4100-bb30-a9f73d07149e 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?
Skip to content

Copilot Chat

链式代理测速实现方案分析

You said: 查看代码并仔细思考,这个项目测速的技术原理是什么?是纯原生还是操控另一个测速工具?

查看代码并仔细思考,这个项目测速的技术原理是什么?是纯原生还是操控另一个测速工具?
2/2
20 references  20个参考文献

Copilot said: 通过分析代码,我可以告诉你这个项目的测速技术原理: ## 技术原理总结 **这是纯原生的测速实现,没有调用外部测速工具。** ### 核心测速逻辑 项目在 `check/platform/speed.go` 中实现了自己的测速功能: ```go func CheckSpeed(httpClient *http.Client,

通过分析代码,我可以告诉你这个项目的测速技术原理:

技术原理总结

这是纯原生的测速实现,没有调用外部测速工具。

核心测速逻辑

项目在 check/platform/speed.go 中实现了自己的测速功能:

Go  
func CheckSpeed(httpClient *http.Client, bucket *ratelimit.Bucket) (int, int64, error) {
    // 创建测速专用客户端
    speedClient := &http.Client{
        Timeout: time.Duration(config.GlobalConfig.DownloadTimeout) * time.Second,
        Transport: httpClient.Transport, // 复用原有的传输层(代理配置)
    }

    // 发起HTTP GET请求到测速URL
    req, err := http.NewRequest("GET", config.GlobalConfig.SpeedTestUrl, nil)
    
    // 记录开始时间
    startTime := time.Now()
    
    // 限速下载和大小限制
    bucketReader := ratelimit.Reader(resp.Body, bucket)
    limitedReader := io.LimitReader(bucketReader, limitSize)
    totalBytes, err = io.Copy(io.Discard, limitedReader) // 下载数据但丢弃
    
    // 计算速度
    duration := time.Since(startTime).Milliseconds()
    speed := int(float64(totalBytes) / 1024 * 1000 / float64(duration)) // KB/s
    
    return speed, totalBytes, nil
}

测速原理

  1. 纯HTTP下载测试:通过HTTP GET请求下载指定大小的数据
  2. 时间计算:记录下载开始和结束时间
  3. 速度计算速度(KB/s) = 下载字节数 / 1024 * 1000 / 耗时(毫秒)
  4. 流量控制:使用 ratelimit 库控制总体下载速度
  5. 数据丢弃:下载的数据通过 io.Discard 直接丢弃,不占用内存

测速数据源

项目提供了灵活的测速地址配置:

  1. 默认使用配置文件中的 speed-test-url
  2. 推荐自建测速服务:项目提供了 Cloudflare Worker 脚本 (doc/cloudflare/worker.js),可以代理 Cloudflare 的测速服务:
    JavaScript
    const speedTestUrl = `https://speed.cloudflare.com/__down?bytes=${bytes}`;
    

集成在整体检测流程中

根据架构图,测速是节点检测流程的重要环节:

Code  代码
订阅链接 → 节点去重 → 测活 → 测速 → 流媒体测试 → 生成结果

只有通过测活检测的节点才会进行测速,测速达标的节点才会进入流媒体检测环节。

总结:这是一个完全自主实现的测速方案,没有依赖 Speedtest.net 等第三方测速工具,而是通过原生的 HTTP 下载测试来测量代理节点的速度。

2/2

You said: 如果我希望增加链式代理测速,帮我思考下实现流程和技术方案会是怎么样的,先不用写代码。技术难点和解决方案

如果我希望增加链式代理测速,帮我思考下实现流程和技术方案会是怎么样的,先不用写代码。技术难点和解决方案
2/2

Copilot said: 基于对当前项目代码的理解,让我分析一下增加链式代理测速的实现流程和技术方案: ## 链式代理测速实现方案 ### 1. 技术架构设计 **链式代理的本质**:将多个代理节点串联,数据流经过 `客户端 → 代理1

基于对当前项目代码的理解,让我分析一下增加链式代理测速的实现流程和技术方案:

链式代理测速实现方案

1. 技术架构设计

链式代理的本质:将多个代理节点串联,数据流经过 客户端 → 代理1 → 代理2 → 目标服务器 的路径。

2. 实现流程设计

Code  代码
配置解析 → 链式连接建立 → 测速执行 → 结果分析 → 性能评估

2.1 配置层面

  • 扩展现有配置文件,支持链式代理组合定义
  • 支持预定义的链式组合和动态组合
  • 配置链式代理的优先级和测试策略

2.2 连接建立

  • 基于现有的 http.Client 架构,扩展 Transport
  • 实现代理链的递归连接:每个代理作为下一个代理的"客户端"
  • 处理不同协议混合:HTTP → SOCKS5 → VMess 等

2.3 测速执行

  • 复用现有的 CheckSpeed 函数框架
  • 传入链式代理的复合 http.Client
  • 保持相同的测速逻辑:下载 → 计时 → 计算速度

3. 核心技术难点与解决方案

难点1: 代理链连接建立复杂性

问题:不同协议间的嵌套连接建立 解决方案

  • 借鉴 mihomo 的代理链实现机制
  • 创建递归的 Dialer 结构:每层代理包装下一层
  • 实现统一的连接接口,屏蔽协议差异

难点2: 错误定位和诊断

问题:链式代理中任一节点失败,难以定位故障点 解决方案

  • 实现分段检测:逐层验证连接可用性
  • 添加详细的错误上下文:记录失败发生在哪一层
  • 提供链路诊断工具:ping 每一跳的延迟

难点3: 超时和性能管理

问题:链式代理的总体超时需要合理分配 解决方案

  • 动态超时计算:根据链长度调整总超时时间
  • 分层超时设置:每层代理设置合理的超时阈值
  • 性能降级策略:超时后自动尝试更短的链路

难点4: 资源消耗和并发控制

问题:链式代理建立连接的资源开销大 解决方案

  • 连接池复用:缓存已建立的链式连接
  • 限制并发数:避免过多链式连接同时建立
  • 智能调度:优先测试高成功率的链式组合

4. 具体技术实现思路

4.1 扩展现有架构

Go  
// 扩展现有的 proxy 结构
type ProxyChain struct {
    Proxies []map[string]any  // 代理链节点列表
    Name    string            // 链名称
    Client  *http.Client      // 复合客户端
}

// 扩展 CheckSpeed 函数
func CheckChainSpeed(chain *ProxyChain, bucket *ratelimit.Bucket) (int, int64, error)

4.2 Transport 层实现  4.2 传输层实现

  • 创建 ChainTransport 实现 http.RoundTripper 接口
  • 递归构建代理链:Transport1(Transport2(Transport3(...)))
  • 处理认证信息在链中的传递

4.3 配置文件扩展

YAML
# 新增链式代理配置段
proxy-chains:
  - name: "chain-1"
    proxies:
      - type: "http"
        server: "proxy1.example.com"
        port: 8080
      - type: "socks5"
        server: "proxy2.example.com" 
        port: 1080
    
chain-test:
  enabled: true
  max-chain-length: 3
  timeout-multiplier: 1.5

5. 性能优化考虑

5.1 智能链组合

  • 根据历史测速结果,智能推荐高性能链组合
  • 避免测试明显会失败的链组合(如两个相同地区的节点)

5.2 缓存机制

  • 缓存链式连接的建立结果
  • 缓存代理节点的可用性状态,避免重复检测

5.3 并行优化

  • 对不同链组合并行测速
  • 但控制单个链内的串行连接建立

6. 用户体验设计

6.1 结果展示

  • 显示完整链路信息:节点A → 节点B → 目标
  • 展示每跳的延迟和整体链路性能
  • 提供链路性价比分析(性能 vs 复杂度)

6.2 配置简化

  • 提供链式代理模板
  • 支持一键生成常用链组合
  • 智能推荐最优链长度

7. 集成现有系统

基于现有的检测流程,链式代理测速可以作为:

  1. 独立检测模式:专门的链式代理测试
  2. 扩展检测模式:在常规测速后,对优质节点进行链式组合测试
  3. 对比检测模式:同时测试单节点和链式性能,提供对比数据

这样的设计既能充分利用现有架构的稳定性,又能为用户提供更强大的代理测试能力。

You said: 详细展开说说http.Transport 扩展的部分,先不要写代码

详细展开说说http.Transport 扩展的部分,先不要写代码

Copilot said: ## http.Transport 扩展详细方案 ### 1. Transport 在 Go

http.Transport 扩展详细方案

1. Transport 在 Go HTTP 中的作用机制

1.1 现有架构理解

在当前 subs-check 项目中:

Code  代码
http.Client -> http.Transport -> 单个代理 -> 目标服务器

http.Transport 实现了 http.RoundTripper 接口,负责:

  • 建立底层网络连接
  • 处理代理配置(通过 Proxy 字段)
  • 管理连接池和复用
  • 处理 TLS 握手

1.2 链式代理的挑战

链式代理需要实现:

Code  代码
http.Client -> ChainTransport -> 代理1 -> 代理2 -> 代理3 -> 目标服务器

每一跳都需要完整的握手和协议协商过程。

2. ChainTransport 架构设计

2.1 核心设计理念

分层抽象:每个代理层都是一个独立的 Transport,但它们的目标不是直接到达最终服务器,而是到达下一个代理。

递归构建:从最内层(最后一个代理)开始,逐层包装:

Code  代码
BaseTransport -> Proxy3Transport -> Proxy2Transport -> Proxy1Transport

2.2 接口设计思路

Go  
type ChainTransport struct {
    // 代理链配置
    proxies []ProxyConfig
    
    // 每一层的 Transport 实例
    transports []http.RoundTripper
    
    // 连接缓存和管理
    connPool *ConnectionPool
    
    // 错误追踪
    errorTracker *ChainErrorTracker
}

3. 连接建立的分层机制

3.1 第一层:基础 Transport

  • 直连到第一个代理服务器
  • 处理最基础的网络连接
  • 管理 TCP 层面的连接池

3.2 第二层:协议适配 Transport

  • 包装第一层,添加代理协议支持
  • 处理 SOCKS5/HTTP CONNECT 握手
  • 将对"目标地址"的请求重定向到"下一个代理地址"

3.3 第三层:链式管理 Transport

  • 协调多个代理层的工作
  • 处理链式认证信息传递
  • 统一错误处理和重试逻辑

4. 具体技术实现思路

4.1 连接建立流程

阶段1:逆向构建连接链

  1. 从最后一个代理开始构建 Transport
  2. 每个代理的 "Dial" 函数指向前一个代理
  3. 第一个代理的 "Dial" 函数指向真实网络

阶段2:正向建立连接

  1. 客户端发起请求到第一个代理
  2. 第一个代理建立到第二个代理的连接
  3. 依此类推,直到建立完整链路

阶段3:数据传输

  1. HTTP 请求沿着建立好的链路传输
  2. 每一跳处理自己的协议封装/解封装
  3. 响应数据原路返回

4.2 协议适配策略

HTTP 代理适配

  • 使用 CONNECT 方法建立隧道
  • 后续数据透明传输
  • 处理 407 代理认证

SOCKS5 代理适配

  • 完成 SOCKS5 握手协议
  • 处理用户名/密码认证
  • 建立数据传输通道

混合协议处理

  • 每层独立处理自己的协议
  • 通过统一的 net.Conn 接口传递连接
  • 协议无关的错误处理机制

5. 连接池和资源管理

5.1 分层连接池设计

问题:传统连接池是针对单一目标的,链式代理有多个中间节点。

解决方案

  • 链路连接池:以整条链路为单位缓存连接
  • 节点连接池:每个代理节点维护独立的连接池
  • 智能复用:相同前缀的链路可以复用部分连接

5.2 资源清理机制

层次化清理

  • 链路级清理:整条链路失效时的清理
  • 节点级清理:单个代理失效时的部分清理
  • 连接级清理:底层网络连接的精确管理

超时管理

  • 建立超时:链路建立的总体时间限制
  • 空闲超时:链路空闲时的保持时间
  • 读写超时:数据传输过程中的超时

6. 错误处理和诊断

6.1 错误分类和定位

网络层错误

  • 无法连接到代理服务器
  • 网络超时或连接重置
  • DNS 解析失败

协议层错误

  • 代理认证失败
  • 协议握手失败
  • 不支持的协议特性

应用层错误

  • HTTP 状态码错误
  • 响应格式错误
  • 业务逻辑错误

6.2 智能错误恢复

分段重试

  • 从失败节点开始重新建立连接
  • 避免重新建立整个链路
  • 保留已成功的部分连接

降级策略

  • 自动移除问题节点
  • 尝试更短的链路配置
  • 回退到单节点模式

7. 性能优化考虑

7.1 连接建立优化

并行握手

  • 在保证协议正确性的前提下,尽可能并行化
  • 预建立连接:根据历史使用模式提前建立连接
  • 连接预热:定期保活重要的链路连接

智能路由

  • 基于历史性能数据选择最优链路
  • 动态调整链路配置
  • 负载均衡机制

7.2 数据传输优化

缓冲管理

  • 适应链式传输的缓冲区大小
  • 避免过多的中间缓冲
  • 流式处理大文件传输

压缩和编码

  • 在适当的层次进行数据压缩
  • 避免重复的编码/解码操作
  • 保持数据完整性

8. 与现有系统的集成点

8.1 配置系统集成

  • 扩展现有的代理配置解析
  • 保持向后兼容性
  • 支持动态配置更新

8.2 监控系统集成

  • 扩展现有的进度显示机制
  • 添加链路状态监控
  • 集成到现有的日志系统

8.3 结果系统集成

  • 扩展 Result 结构体
  • 保持现有的结果格式兼容
  • 添加链式代理特有的指标

9. 测试和验证策略

9.1 单元测试

  • 每个 Transport 层的独立测试
  • Mock 不同协议的代理服务器
  • 异常情况的覆盖测试

9.2 集成测试

  • 真实代理环境的端到端测试
  • 不同协议组合的兼容性测试
  • 性能基准测试

这种分层的 Transport 扩展方案既保持了 Go HTTP 库的设计哲学,又为链式代理提供了强大而灵活的实现基础。

You said: 有一些问题: Subs-Check, [2025/7/23 8:41] 你描述一下怎么实现 Subs-Check, [2025/7/23 8:41] 我能想到的就是你在那个节点上搭一个http服务 Subs-Check, [2025/7/23 11:23] 听不懂,你可以在描述一下嘛 Subs-Check,

有一些问题: Subs-Check, [2025/7/23 8:41] 你描述一下怎么实现 Subs-Check, [2025/7/23 8:41] 我能想到的就是你在那个节点上搭一个http服务 Subs-Check, [2025/7/23 11:23] 听不懂,你可以在描述一下嘛 Subs-Check, [2025/7/23 11:23] 最好画个图 我希望无需额外部署,支持目前所有协议组合。请你直观地深入具体地描述技术方案但不用写代码
3/3

Copilot said: ## 链式代理测速技术方案详解 我理解你的疑问,让我用更直观的方式解释这个方案。**重点是:无需额外部署,纯客户端实现。** ### 1. 核心思路图解 ``` 传统单节点测速: [subs-check客户端] -----> [代理节点] ----->

链式代理测速技术方案详解

我理解你的疑问,让我用更直观的方式解释这个方案。重点是:无需额外部署,纯客户端实现。

1. 核心思路图解

Code  代码
传统单节点测速:
[subs-check客户端] -----> [代理节点] -----> [测速服务器]
                 建立连接      建立连接

链式代理测速:
[subs-check客户端] -----> [代理1] -----> [代理2] -----> [测速服务器]
                 连接1        连接2        连接3

2. 技术实现的本质

不是在节点上搭建HTTP服务,而是让 subs-check 客户端模拟浏览器的行为,通过编程方式建立多层代理连接。

3. 具体实现流程图

Code  代码
步骤1: 配置解析
┌─────────────────┐
│ 用户配置文件    │
│ proxy-chain:    │
│ - 节点A (HTTP)  │
│ - 节点B (SOCKS5)│
│ - 节点C (VMess) │
└─────────────────┘
         │
         ▼

步骤2: 连接建立(关键部分)
┌─────────────────────────────────────────────────────────┐
│                    subs-check 内部                      │
│                                                         │
│ ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌────────┐ │
│ │TCP连接1 │───▶│TCP连接2 │───▶│TCP连接3 │───▶│HTTP请求│ │
│ │到节点A  │    │到节点B  │    │到节点C  │    │到测速  │ │
│ │         │    │         │    │         │    │服务器  │ │
│ └─────────┘    └─────────┘    └─────────┘    └────────┘ │
│     ▲              ▲              ▲              ▲      │
│     │              │              │              │      │
│ ┌───┴────┐    ┌────┴────┐    ┌────┴────┐    ┌────┴───┐ │
│ │协议处理│    │协议处理 │    │协议处理 │    │HTTP    │ │
│ │HTTP    │    │SOCKS5   │    │VMess    │    │处理    │ │
│ │CONNECT │    │握手     │    │握手     │    │        │ │
│ └────────┘    └─────────┘    └─────────┘    └────────┘ │
└─────────────────────────────────────────────────────────┘

4. 详细的连接建立过程

4.1 第一步:连接节点A (HTTP代理)

Code  代码
subs-check 发送:
┌─────────────────────────────────────┐
│ CONNECT 节点B的IP:端口 HTTP/1.1     │
│ Host: 节点B的IP:端口                │
│ Proxy-Authorization: Basic xxx      │
└─────────────────────────────────────┘
         │
         ▼
节点A 响应:
┌─────────────────────────────────────┐
│ HTTP/1.1 200 Connection established │
└─────────────────────────────────────┘

现在 subs-check 和节点B之间有了一个通过节点A的隧道

4.2 第二步:通过节点A连接节点B (SOCKS5)

Code  代码
subs-check 通过节点A发送到节点B:
┌─────────────────────────────────────┐
│ SOCKS5 握手包                       │
│ 0x05 0x01 0x00 (版本+方法数+无认证)  │
└─────────────────────────────────────┘
         │
         ▼
节点B 通过节点A响应:
┌─────────────────────────────────────┐
│ 0x05 0x00 (版本+选择无认证)          │
└─────────────────────────────────────┘

然后 subs-check 继续发送:
┌─────────────────────────────────────┐
│ 连接请求到节点C                     │
│ 0x05 0x01 0x00 0x01 [节点C的IP和端口]│
└─────────────────────────────────────┘

现在有了 subs-check → 节点A → 节点B → 节点C 的连接链路。

4.3 第三步:通过前两个节点连接节点C

这里假设节点C是VMess协议,需要进行VMess握手:

Code  代码
subs-check 通过(节点A→节点B)发送到节点C:
┌─────────────────────────────────────┐
│ VMess 握手数据包                    │
│ [加密的认证信息+目标地址]            │
└─────────────────────────────────────┘
         │
         ▼
节点C 响应VMess确认包

5. 核心技术难点的解决

5.1 "套娃"连接的实现

问题:如何让一个网络连接"穿过"多个代理?

解决方案:使用Go的 net.Conn 接口进行包装

Code  代码
最终的连接对象:
┌─────────────────────────────────────┐
│          VMessConn                  │
│    ┌─────────────────────────────┐  │
│    │         SOCKS5Conn          │  │
│    │  ┌─────────────────────────┐│  │
│    │  │       HTTPConn          ││  │
│    │  │ ┌─────────────────────┐ ││  │
│    │  │ │     RawTCPConn      │ ││  │
│    │  │ └─────────────────────┘ ││  │
│    │  └─────────────────────────┘│  │
│    └─────────────────────────────┘  │
└─────────────────────────────────────┘

每一层 Conn 都实现相同的接口:

  • Read([]byte) (int, error) - 读取数据时自动解包
  • Write([]byte) (int, error) - 写入数据时自动封包
  • Close() error - 关闭时层层向下关闭

5.2 协议识别和处理

subs-check已经支持的协议(基于mihomo):

  • HTTP/HTTPS 代理
  • SOCKS4/SOCKS5 代理
  • Shadowsocks  影子袜子
  • VMess  虚拟机
  • VLESS  更少
  • Trojan  特洛伊木马
  • Hysteria  歇斯底里
  • 等等...

复用现有能力

Code  代码
现有代码结构:
config/proxy.go     - 解析各种协议配置
adapter/           - 各协议的实现
  ├── http.go      - HTTP代理实现
  ├── socks.go     - SOCKS代理实现  
  ├── vmess.go     - VMess实现
  └── ...

链式扩展只需要:
chain/
  └── transport.go  - 组合现有adapter,无需重新实现协议

6. 数据流示意图

Code  代码
测速时的数据流:

1. HTTP请求发起
┌─────────────────┐
│ GET /test HTTP  │ ──┐
│ Host: speed.com │   │
└─────────────────┘   │
                      │
2. 层层封装              │
VMess封装 ──────────────┼──┐
SOCKS5封装 ─────────────┼──┼──┐
HTTP CONNECT ──────────┼──┼──┼──┐
原始TCP ───────────────┼──┼──┼──┼──> 节点A
                      │  │  │  │
3. 节点间传输              │  │  │
节点A解HTTP,转发────────┼──┼──┼──> 节点B  
节点B解SOCKS5,转发─────┼──┼──> 节点C
节点C解VMess,转发──────┼──> 测速服务器
                      │
4. 响应数据原路返回         │
测速数据 <────────────────┘

7. 实际使用场景示例

场景1:绕过多层网络限制

Code  代码
用户网络环境:
公司网络 → 需要通过公司代理 → 然后通过个人VPN → 最后到测速服务器

配置:
chain-proxies:
  - name: "company-to-personal"  
    proxies:
      - {type: http, server: "company-proxy.com", port: 8080}
      - {type: vmess, server: "personal-vps.com", port: 443}

场景2:负载均衡测试

Code  代码
测试不同的代理组合性能:
组合1: [香港节点] → [新加坡节点] → 测速
组合2: [日本节点] → [美国节点] → 测速  
组合3: [德国节点] → [英国节点] → 测速

找出最快的组合路径

8. 与现有架构的无缝集成

Code  代码
现有测速流程:
check.go 调用 → speed.CheckSpeed() → 创建http.Client → 测速

链式测速流程:
check.go 调用 → speed.CheckChainSpeed() → 创建ChainClient → 测速
                                              ↑
                                        内部组装多个代理
                                        但对外接口保持一致

关键优势

  1. 零部署:不需要在任何节点上安装额外软件
  2. 协议无关:支持任意协议组合
  3. 向下兼容:不影响现有单节点测速功能
  4. 配置简单:只需要在配置文件中定义链式组合

这就是纯客户端实现的链式代理测速方案,通过软件层面的连接包装和协议处理,实现多跳代理的性能测试。

Copied!