Files
Meshray-Manager/core/README.md
T
2026-06-30 15:14:37 +08:00

272 lines
12 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.
# 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
→ 创建 WGPluginplugins/wg/wgparse.go
→ 创建 Relay,传入 plugintransport/relay.go
→ 创建 Strategyconnect/strategy.go
→ 创建 ConnManagertransport/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