双向代理架构¶
实现状态:✅ 已实现¶
双向代理架构已完全实现并在生产环境中运行。
架构概览¶
数据流¶
- 客户端发送
ProxyConnect→ 服务器连接目标 → 服务器返回ProxyResponse - 客户端发送
ProxyData→ 服务器写入目标 - 服务器从目标读取 → 服务器加密
ProxyData→ 服务器发送给客户端 - 正确处理来自 WebSocket 和目标 TCP 流的并发读取
技术实现¶
1. Ratchet 并发访问¶
DoubleRatchet 被包装在 Arc<RwLock<DoubleRatchet>> 中以实现线程安全访问:
- WebSocket 读取器任务:解密客户端消息
- 目标读取器任务:加密目标响应
两个操作现在可以使用 SplitRatchet 实现并发进行。
2. 目标读取器任务¶
对于每个代理连接,有一个专用任务从目标读取:
async fn target_reader(
connection_id: u64,
mut target_stream: TcpStream,
ratchet: Arc<RwLock<DoubleRatchet>>,
mut ws_write: impl SinkExt<Message>,
) {
let mut buf = [0u8; 8192];
loop {
match target_stream.read(&mut buf).await {
Ok(0) => break, // EOF
Ok(n) => {
let data = &buf[..n];
let proxy_data = ProxyData {
connection_id,
data: data.to_vec(),
close: false,
};
// 加密并通过 WebSocket 发送
let encrypted = {
let mut ratchet_guard = ratchet.write().await;
ratchet_guard.encrypt(&msg_bytes, PayloadType::ProxyData as u8)
};
ws_write.send(Message::Binary(encrypted)).await.ok();
}
Err(_) => break,
}
}
}
3. 连接生命周期管理¶
每个代理连接维护: - 连接 ID:用于多路复用的唯一标识符 - 目标 TCP 流:到目标服务器的连接 - 目标读取器任务:读取目标响应的异步任务 - 断开时清理:双向正确清理资源
4. 连接池¶
服务器实现了连接池以高效复用资源: - 尽可能复用已建立的连接 - 正确关闭空闲连接 - 高效处理并发连接
修改的文件¶
rvpn-server/src/handler.rs- 使用
Arc<RwLock<DoubleRatchet>>的handle_vpn_traffic handle_proxy_connect生成目标读取器任务- 用于读取目标响应的
target_reader函数 -
连接清理逻辑
-
rvpn-core/src/crypto/ratchet.rs DoubleRatchet为Send以支持异步使用- SplitRatchet 用于并发加密/解密
测试结果¶
- ✅ 基本 HTTP 请求/响应
- ✅ HTTPS 请求/响应
- ✅ 大文件下载
- ✅ 并发多连接
- ✅ 连接超时处理
- ✅ 优雅关闭
- ✅ 错误传播到客户端