PeerLink 使用的网络协议详细说明。
PeerLink 使用多种协议实现 P2P 通信:
graph TB
subgraph "应用层"
APP[P2P Application]
end
subgraph "会话层"
SIG[Signaling Protocol]
P2P[P2P Protocol]
RELAY[Relay Protocol]
end
subgraph "传输层"
WSS[WSS/TLS]
UDP[UDP]
TCP[TCP]
end
subgraph "网络层"
IP[IP]
end
APP --> SIG
APP --> P2P
APP --> RELAY
SIG --> WSS
P2P --> UDP
P2P --> TCP
RELAY --> TCP
WSS --> IP
UDP --> IP
TCP --> IP
信令协议用于会话建立和协商。
sequenceDiagram
participant A as Client A
participant S as Signaling Server
participant B as Client B
A->>S: CONNECT (from_peer_id, to_peer_id)
S->>B: OFFER (from_peer_id, session_id, offer)
B->>S: ANSWER (session_id, answer)
S->>A: ANSWER (session_id, answer)
Note over A,B: 开始 NAT 打洞
{
"type": "offer", // 消息类型: offer, answer, ice, close
"version": "1.0", // 协议版本
"session_id": "sess_abc", // 会话 ID
"from_peer_id": "did:peer:...", // 发送方 Peer ID
"to_peer_id": "did:peer:...", // 接收方 Peer ID
"timestamp": 1234567890, // 时间戳
"signature": "...", // 签名
// Offer/Answer 特定字段
"candidates": [ // ICE 候选
{
"type": "udp", // udp, tcp
"address": "203.0.113.10",
"port": 12345,
"priority": 100
}
],
// 信封
"encryption": {
"algorithm": "AES-256-GCM",
"key_id": "...",
"nonce": "..."
}
}ICE (Interactive Connectivity Establishment) 候选用于 NAT 穿透:
{
"type": "ice",
"session_id": "sess_abc",
"candidate": {
"type": "udp", // udp, tcp, relay
"address": "203.0.113.10",
"port": 12345,
"protocol": "udp", // udp, tcp
"relay_addr": null, // 仅 relay 类型
"priority": 100
}
}点对点数据传输协议。
+----------------+----------------+--------------------+------------------+
| Magic (4B) | Length (4B) | Type (2B) | Flags (2B) |
+----------------+----------------+--------------------+------------------+
| Session ID (16B) | Seq Num (8B) |
+----------------+----------------+--------------------+------------------+
| Timestamp (8B) | Checksum (4B) | Payload (Variable) |
+----------------+----------------+--------------------------------------+
字段说明:
| 字段 | 大小 | 说明 |
|---|---|---|
| Magic | 4B | 魔数 0x504C4E4B ("PLNK") |
| Length | 4B | Payload 长度 |
| Type | 2B | 帧类型 (DATA, ACK, PING, PONG, CLOSE) |
| Flags | 2B | 标志位 |
| Session ID | 16B | 会话 ID |
| Seq Num | 8B | 序列号 |
| Timestamp | 8B | 时间戳 (微秒) |
| Checksum | 4B | CRC32 校验和 |
| Payload | Variable | 有效载荷 |
enum class FrameType : uint16_t {
DATA = 0x01, // 数据帧
ACK = 0x02, // 确认帧
PING = 0x03, // 心跳帧
PONG = 0x04, // 心跳响应
CLOSE = 0x05, // 关闭帧
BATCH = 0x06 // 批量数据帧
};使用选择性重传 (SACK) 实现可靠传输:
Sender Receiver
| |
| DATA (seq=0, len=1000) |
|---------------------------------------->|
| |
| DATA (seq=1000, len=1000) |
|---------------------------------------->|
| |
| ACK (ack=2000, sack=3000:4000,5000:6000)|
|<----------------------------------------|
| |
| DATA (seq=2000, len=1000) |
| DATA (seq=3000, len=1000) |
| DATA (seq=4000, len=1000) |
|---------------------------------------->|
中继协议,用于 NAT 穿透失败时的数据转发。
sequenceDiagram
participant A as Client A
participant R as Relay Server
participant B as Client B
A->>R: CONNECT (session_id, peer_id_b)
A->>R: AUTH (token)
R-->>A: CONNECTED
B->>R: CONNECT (session_id, peer_id_a)
B->>R: AUTH (token)
R-->>B: CONNECTED
Note over A,B: 开始中继数据
+----------------+----------------+----------------+------------------+
| Magic (4B) | Length (4B) | Type (1B) | Reserved (3B) |
+----------------+----------------+----------------+------------------+
| Session ID (16B) |
+----------------+----------------+----------------+------------------+
| Peer ID (64B) |
+----------------+----------------+----------------+------------------+
| Payload (Variable) |
+---------------------------------------------------------+
消息类型:
enum class RelayMessageType : uint8_t {
CONNECT = 0x01,
CONNECTED = 0x02,
DATA = 0x03,
DISCONNECT = 0x04,
PING = 0x05,
PONG = 0x06,
AUTH = 0x07
};Relay 使用 Token 认证:
{
"type": "auth",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"peer_id": "did:peer:...",
"timestamp": 1234567890,
"signature": "..."
}Token 格式:JWT (JSON Web Token)
用于 NAT 类型检测和公网地址发现。
+----------------+----------------+------------------------------------+
| Type (2B) | Length (2B) | Magic Cookie (0x2112A442) |
+----------------+----------------+------------------------------------+
| Transaction ID (12B) |
+------------------------------------------------------------------+
| Attributes (Variable) |
+------------------------------------------------------------------+
消息类型:
0x0001: Binding Request0x0101: Binding Success Response0x0111: Binding Error Response
stateDiagram-v2
[*] --> Test1: 发送 STUN 请求
Test1 --> Test2: 收到响应,地址不变
Test1 --> Symmetric: 收到响应,地址改变
Test2 --> Test3: 从另一端口发送请求
Test2 --> Restricted: 无响应
Test3 --> FullCone: 收到响应
Test3 --> Restricted: 无响应
NAT 类型判定:
- Full Cone: 任何外部主机都可以通过映射地址通信
- Restricted Cone: 只有曾经通信过的外部主机可以通信
- Port-Restricted Cone: 只有曾经通信过的外部主机和端口可以通信
- Symmetric: 每个目标地址/端口对都有独立的映射
所有连接都使用 TLS 1.3 加密:
Client Server
| |
| ClientHello |
|----------------------------------------------->|
| |
| ServerHello |
| [Certificate] |
| [Finished] |
|<-----------------------------------------------|
| |
| [Finished] |
|----------------------------------------------->|
| |
| Application Data |
|<=============================================>|
每个消息都包含签名:
{
"payload": "base64encodedpayload",
"sender": "did:peer:...",
"recipient": "did:peer:...",
"timestamp": 1234567890,
"nonce": "randomnonce",
"signature": "ed25519signature"
}签名算法:Ed25519
// 批量帧格式
struct BatchFrame {
uint32_t count; // 子帧数量
SubFrame frames[count]; // 子帧数组
};
struct SubFrame {
uint64_t seq; // 序列号
uint32_t length; // 长度
uint8_t data[]; // 数据
};使用共享内存和引用计数避免数据拷贝:
class ZeroCopyBuffer {
public:
std::shared_ptr<std::vector<uint8_t>> data;
size_t offset;
size_t length;
};