# MeshRay-Core 架构规范 > Core 是通用的数据传输引擎,通过 ProtocolPlugin 接口适配不同协议。当前默认内置 WG 插件。 --- ## 一、目录结构 ``` core/ ├── core.go # 进程入口 ├── engine.go # 引擎实例 ├── metrics.go # 监控指标 │ ├── connect/ # 建连层 │ ├── strategy.go # 策略调度 │ ├── stun.go # STUN 协议 │ ├── direct.go # Layer 1 │ ├── fake_tcp.go # Layer 2 │ ├── real_tcp.go # Layer 3 │ ├── turn.go # Layer 4/6/7 │ ├── turn_quic.go # Layer 5 │ ├── ice.go # Layer 8 │ └── ws.go # Layer 9 │ ├── transport/ # 传输层 │ ├── conn_manager.go # 连接索引 │ ├── relay.go # 转发循环 │ └── plugin.go # Plugin 接口 │ └── plugins/ # 协议插件 └── wg/ └── wgparse.go # WG 插件实现 ``` --- ## 二、各文件职责 ### 2.1 根目录(4 个文件) | 文件 | 职责 | 持有什么 | 不做什么 | |------|------|---------|----------| | `core.go` | 进程入口,管理多个 Engine | `map[engineID]*Engine` | 不做建连、不转发数据 | | `engine.go` | 一个组网的引擎实例 | strategy、conn_manager、relay、plugin | 不直接调用 connect,由 relay 调用 | | `metrics.go` | 监控指标采集 | 原子计数器(连接数、字节数、切换次数) | 不做业务逻辑 | **关键关系**: - `core.go` 持有多个 `engine.go` - `internal/ctr/ctr.go` 直接调用 `core.go` 和 `engine.go` (进程内函数调用) - `engine.go` 持有 connect/、transport/、plugins/ 的实例 ### 2.2 connect/(9 个文件)— 建连层 **职责**:通过各种网络方式建立连接,最终返回 `net.Conn`。 **对外暴露的唯一入口**:`strategy.go` 的 `Connect()` 方法。其他 connect 文件只被 `strategy.go` 调用。 | 文件 | 对应层级 | 职责 | 返回什么 | |------|---------|------|---------| | `strategy.go` | 全部 | 按优先级尝试各层,不通自动切换,定期探测恢复 | `net.Conn` + 当前层级名 | | `stun.go` | 被 direct/ice 调用 | STUN 协议:发送 Binding Request,获取本机公网地址 | `*net.UDPAddr`(地址,不是连接) | | `direct.go` | Layer 1 | 调用 stun 获取候选地址,然后 UDP 打洞 | `net.Conn` | | `fake_tcp.go` | Layer 2 | UDP 包外层封装 TCP 头部,欺骗防火墙 | `net.Conn` | | `real_tcp.go` | Layer 3 | 真正的 TCP 直连打洞 | `net.Conn` | | `turn.go` | Layer 4/6/7 | TURN 协议协商(Allocate/Permission/ChannelBind),参数区分 UDP/TCP/TLS | `net.Conn` | | `turn_quic.go` | Layer 5 | TURN-QUIC 私有扩展(RFC 9000) | `net.Conn` | | `ice.go` | Layer 8 | ICE 协商 + WebRTC DataChannel,内部调用 stun 收集候选 | `net.Conn` | | `ws.go` | Layer 9 | WS/WSS 握手 + 帧收发 + 身份标识 | `net.Conn` | **9 层完整编号**: | 层级 | 链路名称 | 文件 | 传输方式 | 穿透力 | |------|---------|------|---------|--------| | 1 | Direct-UDP | direct.go | P2P 直连 | 弱(性能最好) | | 2 | Direct-FakeTCP | fake_tcp.go | P2P 直连 | 弱 | | 3 | Direct-RealTCP | real_tcp.go | P2P 直连 | 中 | | 4 | TURN-UDP | turn.go | 中继 | 中 | | 5 | TURN-QUIC | turn_quic.go | 中继 | 中 | | 6 | TURN-TCP | turn.go | 中继 | 强 | | 7 | TURN-TLS | turn.go | 中继 | 强 | | 8 | WebRTC | ice.go | ICE/TURN | 强 | | 9 | WS/WSS | ws.go | 隧道 | 最强(兜底) | **strategy.go 的自动切换逻辑**: - 单包超时 500ms → 切到下一层 - 10s 滑动窗口丢包率 > 10% → 切到下一层 - 当前在第 N 层时,每 30s 探测 Layer 1 → 连续 2 次成功直接切回 Layer 1(不逐层回退) **stun.go 的特殊地位**:唯一被多处调用的 connect 文件(direct.go 和 ice.go 都需要它),所以独立存在。 ### 2.3 transport/(3 个文件)— 传输层 **职责**:用 `net.Conn` 转发数据。不感知具体协议,通过 ProtocolPlugin 接口适配。 | 文件 | 职责 | 不做什么 | |------|------|---------| | `conn_manager.go` | 连接索引:`peer_key → net.Conn` 的映射 | 不做建连、不转发数据 | | `relay.go` | Read/Write 循环:从本地端口收包 → 查路由 → 通过 conn 发送;从 conn 收包 → 发到本地端口 | 不做建连 | | `plugin.go` | 定义 ProtocolPlugin 接口 | 不实现任何协议 | **relay.go 的工作流程**: ``` 本地端口收到 WG 密文包 → 调用 plugin.IsControlPacket() 判断包类型 → true:控制包,按已建链路透传 → 调用 plugin.IsDataPacket() 判断 → true:调用 plugin.ExtractRouteID() 提取路由标识 → 查路由标识映射表 → 发往对应本地端口 → 都不是:丢弃 ``` **关键**:relay.go 不知道 WireGuard,不知道 receiver index,只知道 route_id。 ### 2.4 plugins/wg/(1 个文件)— 协议插件 **职责**:实现 ProtocolPlugin 接口,处理 WG 协议特有的包解析。 | 文件 | 职责 | 不做什么 | |------|------|---------| | `wgparse.go` | 实现 `IsDataPacket`/`ExtractRouteID`/`IsControlPacket` | 不做建连、不转发数据 | **WG 插件的具体实现**: | 方法 | 逻辑 | |------|------| | `IsControlPacket(packet)` | `packet[0]` ∈ {1, 2, 3} → true | | `IsDataPacket(packet)` | `packet[0]` == 4 → true | | `ExtractRouteID(packet)` | 读取 `packet[4:8]`,网络字节序解析为 uint32(即 WG receiver index) | ### 2.5 plugins/wg/(1 个文件) | 文件 | 职责 | |------|------| | `wgparse.go` | WireGuard 数据包解析和封装 | --- ## 三、分层架构图 ``` ┌─────────────────────────────────────────────────────────┐ │ internal/ctr/ctr.go │ │ 直接调用 Core (进程内函数调用) │ └────────────────────────┬────────────────────────────────┘ │ 函数调用 ┌────────────────────────▼────────────────────────────────┐ │ core.go │ │ 管理多个 Engine 实例 │ └───┬─────────────────────────────────────────────────────┘ │ 每个组网一个 Engine ▼ ┌─────────────────────────────────────────────────────────┐ │ engine.go │ │ 持有:strategy + conn_manager + relay + plugin │ │ 协调 connect/ 和 transport/ 工作 │ └───┬─────────────────────────────────────────────────────┘ │ ├──────────────────────────────────────────┐ ▼ ▼ ┌───────────────────────┐ ┌───────────────────────┐ │ connect/ │ │ transport/ │ │ 建连层 │ │ 传输层 │ │ │ │ │ │ strategy.go │ 返回 │ relay.go │ │ ├─ direct.go (L1) │ net.Conn├─ plugin.go │ │ ├─ fake_tcp.go (L2) │────────►│ │ ProtocolPlugin │ │ ├─ real_tcp.go (L3) │ │ │ │ │ ├─ turn.go (L4/6/7) │ │ 插件调用 │ │ ├─ turn_quic.go(L5) │ │ ▼ │ │ ├─ ice.go (L8) │ │ plugins/wg/ │ │ └─ ws.go (L9) │ │ └─ wgparse.go │ │ │ │ │ │ stun.go (被 direct/ice 调用) │ conn_manager.go │ └───────────────────────┘ └───────────────────────┘ ``` --- ## 四、调用关系 ### 4.1 Engine 创建时 ``` engine.go → 创建 WGPlugin(plugins/wg/wgparse.go) → 创建 Relay,传入 plugin(transport/relay.go) → 创建 Strategy(connect/strategy.go) → 创建 ConnManager(transport/conn_manager.go) ``` ### 4.2 Bind 流程 ``` ctr 直接调用:Bind() → engine.go 接收函数调用 → engine.go 调用 strategy.Connect() → strategy 按优先级尝试各层 → Layer 1: direct.go 调用 stun.go 获取候选,尝试 UDP 打洞 → 不通?→ Layer 4: turn.go 调用 TURN 协商 → 不通?→ Layer 9: ws.go 调用 WS 握手 → 返回 net.Conn + 当前层级名 → engine.go 把 net.Conn 注册到 conn_manager → engine.go 启动 relay 的 Read/Write 循环 ``` ### 4.3 数据转发流程 ``` WG 发出密文包 → 本地端口 → relay.go 收到 → 调用 plugin.IsControlPacket() → true:按已建链路透传(conn_manager 查 conn) → 调用 plugin.IsDataPacket() → true:调用 plugin.ExtractRouteID() 获取 route_id → 查路由标识映射表 → 找到本地端口 → 发送 → 都不是:丢弃 ``` --- ## 五、通用层与插件层的边界 | 层 | 知道什么 | 不知道什么 | |---|---------|-----------| | **connect/** | 网络协议(STUN/TURN/WS/WebRTC) | WireGuard、route_id | | **transport/** | net.Conn、route_id、ProtocolPlugin 接口 | WireGuard、receiver index | | **plugins/wg/** | WG 包格式、receiver index | 网络连接、net.Conn | | **engine.go** | 协调 connect/ 和 transport/ | WG 包格式细节 | **如果将来要支持其他协议**: - 新建 `plugins/xxx/xxxparse.go` - 实现 `ProtocolPlugin` 接口的三个方法 - `engine.go` 里换成 `xxx.NewPlugin()` - connect/、transport/、core.go 的代码完全不用改 --- ## 六、Core 接口(直接被 ctr 调用) | 方法 | 调用方 | 说明 | |------|--------|------| | `CreateEngine` | ctr | 创建一个 Engine 实例(直接函数调用) | | `Bind` | ctr | 为每个 Peer 开启本地端口,开始建链 | | `Unbind` | ctr | 停止指定 Peer 的端口监听 | | `Start` | ctr | 启动转发主循环 | | `Stop` | ctr | 停止 Engine | | `GetStatus` | ctr | 查询 Engine 状态 | | `NotifyPeerInfo` | ctr | 下发对端候选地址和 route_id | **实现位置**: - 所有方法都在 `engine.go` 中实现 - `core.go` 提供 Engine 实例管理 - ctr通过`coreInst.CreateEngine(...)`直接调用 --- ## 七、文件清单汇总 | 目录 | 文件数 | 文件 | |------|--------|------| | 根目录 | 3 | core.go, engine.go, metrics.go | | connect/ | 9 | strategy.go, stun.go, direct.go, fake_tcp.go, real_tcp.go, turn.go, turn_quic.go, ice.go, ws.go | | transport/ | 3 | conn_manager.go, relay.go, plugin.go | | plugins/wg/ | 1 | wgparse.go | | **总计** | **16** | | **已删除的文件**: - ~~grpc_service.go~~ - 不再需要(改为直接函数调用) - ~~pool/connpool.go~~ - 不再需要(无连接池) - ~~proto/core.proto~~ - 不再需要 gRPC