# p2p-socket-rust **Repository Path**: xy506/p2p-socket-rust ## Basic Information - **Project Name**: p2p-socket-rust - **Description**: 基于 Wireboy.Socket.P2PSocket 的 Rust 完整重构 —— 内网穿透、端口转发与端口发布服务,附带 Web 管理面板 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-13 - **Last Updated**: 2026-06-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README --- AIGC: ContentProducer: '001191110102MAD55U9H0F10002' ContentPropagator: '001191110102MAD55U9H0F10002' Label: '1' ProduceID: 'd2dfacfa-75d5-4c67-bed0-53dfc2a5466e' PropagateID: 'd2dfacfa-75d5-4c67-bed0-53dfc2a5466e' ReservedCode1: '619c3384-ea2f-4fdd-a12d-fa405962de96' ReservedCode2: '619c3384-ea2f-4fdd-a12d-fa405962de96' --- # P2P Socket — Rust 重构版 > 基于 [Wireboy.Socket.P2PSocket](https://github.com/hemaju/Wireboy.Socket.P2PSocket) 的 Rust 完整重构项目,提供内网穿透、端口转发与端口发布服务,附带 Web 管理面板。 ## 特性 - **P2P 隧道**:客户端间通过服务器中继建立加密隧道,实现内网穿透 - **端口映射**:客户端本地端口映射到远程客户端的指定端口 - **端口发布**:将客户端本地端口发布到服务器公网,外部可直接访问 - **UDP 中继**:支持 P2P 打洞模式,通过 UDP 中继实现低延迟数据转发,含 NAT 重映射自动跟踪 - **Web 管理面板**:暗色主题 SPA,全中文界面,Bearer Token 认证,实时管控服务端 - **安全防护**:蜜罐端口独立监听自动拉黑、Web API Token 认证、协议帧长度上限防护 - **高性能**:Rust + tokio 异步运行时,8KB 缓冲区 + u32 协议帧,实测本地 ~96 MB/s - **跨平台**:支持 Windows / Linux(x86_64),单文件部署,零依赖 --- ## 目录 - [系统架构](#系统架构) - [项目结构](#项目结构) - [通信协议](#通信协议) - [命令码定义](#命令码定义) - [编译指南](#编译指南) - [配置说明](#配置说明) - [部署指南](#部署指南) - [Web 管理面板](#web-管理面板) - [API 接口文档](#api-接口文档) - [安全审计](#安全审计) - [使用示例](#使用示例) - [致谢](#致谢) --- ## 系统架构 ``` ┌─────────────────────────┐ │ Web 管理面板 │ │ (axum, 暗色主题 SPA) │ │ 端口 9090 (可配) │ └───────────┬─────────────┘ │ ┌─────────────────▼─────────────────┐ │ P2P Server │ │ │ │ ┌──────────────┐ ┌─────────────┐ │ │ │ TCP 监听 │ │ 端口发布 │ │ │ │ 命令调度 │ │ 动态监听 │ │ │ └──────┬───────┘ └──────┬──────┘ │ │ │ │ │ │ ┌──────▼───────┐ │ │ │ │ 隧道中继管理 │ │ │ │ │ start_relay │ │ │ │ └──────────────┘ │ │ │ DashMap 存储: │ │ │ clients / tunnels / │ │ │ port_publishes / │ │ │ blacklist / logs │ │ └────┬──────────┬──────────┘ │ │ ┌──────────┘ └──────────┐ │ │ ┌────────▼────────┐ ┌───────▼──────────┐ │ P2P Client A │ │ P2P Client B │ │ (发起端) │ P2P 隧道 │ (目标端) │ │ │◄───────────►│ │ │ 本地监听: │ │ 目标服务: │ │ 3588→[B]:3389 │ │ localhost:3389 │ │ │ │ │ │ 端口发布: │ │ 端口发布: │ │ 本地22→服务器10022│ │ 本地80→服务器8080 │ └───────────────────┘ └───────────────────┘ ``` ### 架构要点 | 组件 | 技术栈 | 职责 | |------|--------|------| | **p2p-core** | tokio, bytes, dashmap | 协议编解码、命令调度、配置解析、数据模型、隧道管理 | | **p2p-server** | tokio, axum, dashmap | TCP 服务端、命令处理、Web 管理面板、端口发布、日志管理 | | **p2p-client** | tokio, dashmap | 连接服务端、登录认证、心跳保活、本地端口监听、P2P 隧道、端口发布 | ### 工作流程 ``` 1. 服务端启动 → 监听 TCP 端口 + 启动 Web 面板 2. 客户端连接 → 发送 Login 命令(名称+令牌)→ 服务端验证并注册 3. 客户端心跳 → 每 5 秒发送 Heart 命令 → 服务端更新 last_heartbeat 4. 端口映射 → 客户端监听本地端口 → 收到连接后发送 P2PConnect → 服务器协调中继 5. 端口发布 → Web 面板添加规则 → 服务端监听公网端口 → 外部连接时通知客户端 → 客户端连接本地端口 → 双向数据中继 6. 隧道关闭 → 中继双方向均结束 → 自动清理 tunnel_infos 条目 ``` --- ## 项目结构 ``` p2p-socket-rust/ ├── Cargo.toml # Workspace 根配置 ├── p2p-core/ # 核心库 │ ├── Cargo.toml │ └── src/ │ ├── lib.rs # 模块重导出 │ ├── protocol.rs # 数据包编解码(Packet, PacketReader, u32 data_len, MAX_DATA_LEN) │ ├── command.rs # 命令 trait、调度器、CommandCode 枚举 │ ├── config.rs # INI 配置解析(ServerConfig, ClientConfig) │ ├── models.rs # 数据模型(ClientInfo, PortPublish 等) │ ├── inject.rs # 全局依赖注入(OnceLock + DashMap) │ ├── tunnel.rs # 隧道管理(TunnelPair, start_relay + on_done 回调) │ ├── udp_relay.rs # UDP 中继(NAT 重映射追踪、TOCTOU 安全、watch 停止) │ ├── buffer.rs # 缓冲区常量统一(TCP_RELAY_BUF_SIZE 等) │ └── error.rs # 错误类型定义 ├── p2p-server/ # 服务端 │ ├── Cargo.toml │ └── src/ │ ├── main.rs # 入口(CLI 参数、蜜罐独立监听、Ctrl+C 优雅停止) │ ├── server.rs # P2pServer 结构体、连接/端口发布/隧道管理 │ ├── commands/ │ │ ├── mod.rs # 命令注册 │ │ ├── cmd_login.rs # 登录处理 │ │ ├── cmd_heartbeat.rs# 心跳处理 │ │ ├── cmd_p2p_connect.rs # P2P 连接协调(含隧道/UDP清理回调) │ │ ├── cmd_p2p_transfer.rs # P2P 数据转发(try_send 非阻塞) │ │ ├── cmd_0x0211.rs # 端口发布请求处理 │ │ ├── cmd_0x0212.rs # 端口发布数据转发(Closed/Full 区分处理) │ │ └── cmd_log.rs # 日志消息 │ └── web/ │ ├── mod.rs # Web 路由注册 + Bearer Token 认证中间件 │ ├── routes.rs # API 处理函数(20+ 接口, UUID v4 token) │ └── index.html # 前端 SPA(暗色主题,中文界面) ├── p2p-client/ # 客户端 │ ├── Cargo.toml │ └── src/ │ ├── main.rs # 入口(CLI 参数) │ ├── client.rs # P2PClient 主逻辑(pending_p2p_data 暂存、端口发布) │ └── tunnel.rs # 客户端隧道管理 ├── config/ # 运行时配置与日志 │ ├── server.ini # 服务端配置 │ ├── client.ini # 客户端配置 │ └── logs/ # 服务端日志文件 └── p2p-plugins/ # 插件(预留) ├── p2p-encryption/ └── p2p-pipe/ ``` --- ## 通信协议 ### 线路格式(大端序) ``` ┌──────────┬──────────┬──────────┬──────────┬──────────┐ │ Header │ Cmd Type │ Data Len │ Data │ Footer │ │ 0x56 0x56│ u16 BE │ u32 BE │ bytes │ 0x05 │ │ 2 bytes │ 2 bytes │ 4 bytes │ N bytes │ 1 byte │ └──────────┴──────────┴──────────┴──────────┴──────────┘ ``` - 最小帧长度:9 字节(Data 为空时) - 帧总长度:`8 + data_len + 1` 字节 - Header 标识:`0x56 0x56` - Footer 标识:`0x05` - Cmd Type 和 Data Len 均为 **大端序(Big-Endian)** - **Data Len 使用 u32**(4 字节),支持单帧最大 ~4GB 数据,协议层限制单帧数据不超过 16MB(`MAX_DATA_LEN`) ### PacketReader 解码逻辑 - 维护 `BytesMut` 缓冲区(初始 8192 字节) - 从异步流中 `feed()` 数据 - `try_decode()` 扫描有效帧(容错模式,不会因坏字节断开连接): - Data Len 超过 `MAX_DATA_LEN`(16MB)→ 跳过帧头,记录警告 - Header 不匹配 → 跳过 1 字节继续扫描 - Footer 不匹配 → 跳过整帧,记录警告(不断开连接) - 帧完整 → 提取 `Packet { command_type, data }` --- ## 命令码定义 | 枚举值 | Hex | 说明 | 方向 | |--------|-----|------|------| | `Heart` | `0x0052` | 心跳 Ping/Pong | 双向 | | `Login` | `0x0101` | 登录(名称+令牌) | 客户端→服务端 | | `LoginToken` | `0x0102` | Token 登录 | 预留 | | `LoginSync` | `0x0103` | 登录同步 | 服务端→客户端 | | `LoginAnonymous` | `0x0104` | 匿名登录 | 预留 | | `P2PConnect` | `0x0201` | P2P 连接协商 | 双向 | | `P2PTransfer` | `0x0202` | P2P 数据转发 | 双向 | | `PortMapRequest` | `0x0211` | 端口发布请求 | 双向 | | `PortMapTransfer` | `0x0212` | 端口发布数据转发 | 双向 | | `LogMessage` | `0x0301` | 日志消息 | 服务端→客户端 | ### 关键命令数据格式 **Login(客户端→服务端)** ``` [name_len: u8][name: bytes][token_len: u8][token: bytes] ``` **LoginSync(服务端→客户端)** ``` [client_name: bytes] // 返回分配的客户端名称 ``` **Heartbeat** ``` 空 Data (Ping) / b"pong" (Pong) ``` **P2PConnect Step 1(源客户端→服务端)** ``` [1: u8][token: u64 LE][dest_len: u8][dest_client: bytes][port: u16 LE][p2p_type: u8] ``` **P2PConnect Step 2 通知(服务端→目标客户端)** ``` [2: u8][token: u64 LE][relay_port: u16 LE] ``` **P2PConnect Step 3 响应(服务端→源客户端)** ``` [token: u64 LE][relay_port: u16 LE][p2p_type: u8][3: u8] ``` **P2PTransfer(客户端→服务端)** ``` [token: u64 LE][dest_len: u8][dest_client: bytes][payload: bytes] ``` **PortMapRequest(服务端→客户端,请求连接本地端口)** ``` [token_len: u32 LE][token: bytes][port: i32 LE][remote_ep_len: u32 LE][remote_ep: bytes] ``` **PortMapRequest 响应(客户端→服务端)** ``` [token_len: u32 LE][token: bytes][success: u8][error_len: u32 LE][error: bytes] ``` **PortMapTransfer(双向,端口发布数据转发)** ``` [direction: u8][token_len: u32 LE][token: bytes][data_len: u32 LE][data: bytes] ``` > 注意:P2PConnect 和 P2PTransfer 中的 token/port 字段使用 **小端序(Little-Endian)**,与帧头的 Cmd Type/Data Len 大端序不同。 --- ## 编译指南 ### 环境要求 | 依赖 | 版本要求 | 说明 | |------|---------|------| | Rust | >= 1.70 | 推荐 stable 工具链 | | Cargo | 随 Rust 安装 | 包管理器 | | MSVC | 最新 | Windows 编译需要(或 GNU) | ### 安装 Rust ```bash # Linux / macOS curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Windows(访问 https://rustup.rs 下载 rustup-init.exe) ``` ### 编译 ```bash cd p2p-socket-rust # Debug 编译(快速,适合开发) cargo build # Release 编译(优化,适合部署) cargo build --release # 仅编译服务端 cargo build --release -p p2p-server # 仅编译客户端 cargo build --release -p p2p-client ``` ### 编译产物 | 文件 | 路径 | 说明 | |------|------|------| | `p2p-server` / `p2p-server.exe` | `target/release/` | 服务端可执行文件 | | `p2p-client` / `p2p-client.exe` | `target/release/` | 客户端可执行文件 | --- ## 配置说明 ### 服务端配置 `config/server.ini` ```ini [server] port=3488 # TCP 监听端口 honey_port=3489 # 蜜罐端口(可选,连接即拉黑) need_token=true # 是否要求客户端令牌认证 [client] item1_name=ClientA # 客户端名称 item1_token=token_aaa # 认证令牌 item2_name=ClientB item2_token=token_bbb ``` | 配置项 | 必填 | 默认值 | 说明 | |--------|------|--------|------| | `port` | 否 | 5150 | TCP 服务端口 | | `honey_port` | 否 | 无 | 蜜罐端口,连接此端口的 IP 自动拉黑 | | `need_token` | 否 | false | 是否启用令牌认证 | | `itemN_name` | 是* | — | 第 N 个客户端名称 | | `itemN_token` | 是* | — | 第 N 个客户端令牌 | > *当 `need_token=true` 时,客户端必须在此配置对应的名称和令牌才能登录。认证账号可通过 Web 面板动态添加,自动保存到 server.ini。 ### 客户端配置 `config/client.ini` ```ini [Common] ServerAddress=your-server.com:3488 # 服务端地址 ClientName=ClientA # 客户端名称(需与服务端配置匹配) Token=token_aaa # 认证令牌 AllowPort=0-0 # 允许端口范围(0-0=全部) [PortMapItem] # 格式: 监听端口->类型@[目标客户端]:目标端口 # 类型: 0=TCP直连, 1=P2P打洞 3588->[ClientB]:3389 # 本地 3588 → ClientB 的 3389 端口(TCP) 3589->1@[ClientB]:22 # 本地 3589 → ClientB 的 22 端口(P2P) ``` | 配置项 | 必填 | 默认值 | 说明 | |--------|------|--------|------| | `ServerAddress` | 否 | 127.0.0.1:5150 | 服务端地址和端口 | | `ClientName` | 否 | unnamed | 客户端标识名称 | | `Token` | 否 | 空 | 认证令牌 | | `AllowPort` | 否 | 0-0 | 允许的端口范围 | | `PortMapItem` | 否 | 无 | 端口映射规则 | --- ## 部署指南 ### 服务端部署 #### Linux(systemd 服务) ```bash # 1. 上传文件 mkdir -p /opt/p2p-server/config cp p2p-server /opt/p2p-server/ cp server.ini /opt/p2p-server/config/ chmod +x /opt/p2p-server/p2p-server # 2. 创建 systemd 服务 cat > /etc/systemd/system/p2p-server.service << 'EOF' [Unit] Description=P2P Socket Server After=network.target [Service] Type=simple WorkingDirectory=/opt/p2p-server ExecStart=/opt/p2p-server/p2p-server --config config/server.ini --web-port 9090 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF # 3. 启动服务 systemctl daemon-reload systemctl enable p2p-server systemctl start p2p-server systemctl status p2p-server # 4. 开放防火墙 firewall-cmd --permanent --add-port=3488/tcp # TCP 服务端口 firewall-cmd --permanent --add-port=9090/tcp # Web 管理端口 firewall-cmd --reload ``` #### Windows ```powershell # 直接运行 .\p2p-server.exe --config config\server.ini --web-port 9090 # 注册为 Windows 服务(使用 NSSM) nssm install P2PServer "C:\p2p-server\p2p-server.exe" nssm set P2PServer AppDirectory "C:\p2p-server" nssm set P2PServer AppParameters "--config config\server.ini --web-port 9090" nssm start P2PServer ``` ### 客户端部署 #### Linux ```bash # 直接运行 ./p2p-client --config config/client.ini # 或注册为 systemd 服务 cat > /etc/systemd/system/p2p-client.service << 'EOF' [Unit] Description=P2P Socket Client After=network.target [Service] Type=simple WorkingDirectory=/opt/p2p-client ExecStart=/opt/p2p-client/p2p-client --config config/client.ini Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF ``` #### Windows ```powershell .\p2p-client.exe --config config\client.ini ``` ### 注意事项 - 服务端监听端口可通过 Web 面板「设置」页面在线修改,无需重启 - 端口发布功能需要在服务端防火墙开放对应端口 - SELinux 可能阻止从 `/root/` 目录运行二进制文件,建议放在 `/usr/local/bin/` 或 `/opt/` - 无法覆盖正在运行的二进制文件,需先 `systemctl stop` 再替换 --- ## Web 管理面板 ### 访问方式 浏览器打开 `http://<服务端IP>:9090` - 默认密码:`admin` - 可通过 `--web-password` 参数修改 ### 功能模块 | 模块 | 功能 | |------|------| | **仪表盘** | 在线客户端、活跃隧道、端口映射/发布数、黑名单统计 | | **在线客户端** | 实时查看已连接客户端,支持踢出 | | **客户端认证** | 管理认证账号(增删改),自动保存到 server.ini | | **隧道列表** | 查看当前活跃 P2P 隧道 | | **端口转发** | 客户端端口映射规则管理 | | **端口发布** | 将客户端本地端口发布到服务端公网(动态监听) | | **系统日志** | 查看与搜索运行日志,自动清理(保留 7 天) | | **日志级别** | 在线调整日志级别(trace/debug/info/warn/error) | | **黑名单** | 查看/移除被拉黑的 IP | | **设置** | 修改监听端口、Web 密码等运行参数 | ### 界面特性 - 暗色主题(深蓝背景) - 全中文界面 - 自动刷新(每 5 秒) - 模态对话框 / Toast 通知 --- ## API 接口文档 所有接口返回 `Content-Type: application/json`。 ### 登录认证 **POST** `/api/login` ```json { "username": "admin", "password": "admin" } // 成功 → { "ok": true, "token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" } // 失败 → { "ok": false, "error": "用户名或密码错误" } ``` > 登录成功后返回 UUID v4 Token,后续所有 `/api/*` 请求需携带 `Authorization: Bearer ` 请求头。Token 存储在服务端内存中,服务重启后失效。 ### 仪表盘统计 **GET** `/api/stats` ```json { "clients": 2, "tunnels": 0, "port_mappings": 1, "port_publishes": 1, "blacklist": 0 } ``` ### 在线客户端 **GET** `/api/clients` — 获取列表 **DELETE** `/api/client/{client_id}` — 踢出客户端 ### 客户端认证管理 **GET** `/api/auth-clients` — 获取列表 **POST** `/api/auth-clients` — 新增(`{ "name": "C", "token": "xxx" }`) **PUT** `/api/auth-clients` — 修改令牌 **DELETE** `/api/auth-clients/{name}` — 删除 > 增删改操作自动持久化到 server.ini。 ### 端口转发 **GET** `/api/port-mappings` **POST** `/api/port-mappings` — 新增(`{ "client_id", "listen_port", "target_client", "target_port", "p2p_type" }`) **DELETE** `/api/port-mappings/{id}` ### 端口发布 **GET** `/api/port-publishes` **POST** `/api/port-publishes` — 新增(`{ "client_name", "client_port", "server_port" }`) **DELETE** `/api/port-publishes/{id}` ### 隧道列表 **GET** `/api/tunnels` ### 系统日志 **GET** `/api/logs` — 获取日志列表 **GET** `/api/log-level` — 获取当前日志级别 **PUT** `/api/log-level` — 设置日志级别(`{ "level": "debug" }`) ### 黑名单 **GET** `/api/blacklist` **DELETE** `/api/blacklist/{ip}` ### 设置 **GET** `/api/settings` — 获取服务端设置 **PUT** `/api/settings` — 修改设置(监听端口等) --- ## 使用示例 ### 场景 1:通过 A 机器访问 B 机器的 RDP ``` 你的电脑 ──► A机器(客户端A):3588 ──P2P隧道──► B机器(客户端B):3389 ``` **B 机器**(被控端)client.ini: ```ini [Common] ServerAddress=your-server.com:3488 ClientName=ClientB Token=token_bbb ``` **A 机器**(控制端)client.ini: ```ini [Common] ServerAddress=your-server.com:3488 ClientName=ClientA Token=token_aaa [PortMapItem] 3588->[ClientB]:3389 ``` 然后 `mstsc /v:A机器IP:3588` 连接远程桌面。 ### 场景 2:通过端口发布从外网访问内网 SSH ``` 外部网络 ──► 服务端:10022 ──端口发布──► 客户端:22(SSH) ``` 1. 在 Web 面板「端口发布」中添加规则:客户端 ClusterA,本地端口 22,服务端端口 10022 2. 防火墙开放 10022 端口 3. `ssh user@your-server.com -p 10022` 即可访问内网 SSH ### 命令行参数速查 **服务端** ``` p2p-server [选项] --config 配置文件路径 默认: config/server.ini --web-port Web 面板端口 默认: 8080 --web-password Web 管理密码 默认: admin --no-web 禁用 Web 面板 默认: false ``` **客户端** ``` p2p-client [选项] --config 配置文件路径 默认: config/client.ini --name 覆盖客户端名称 默认: 使用配置文件 --server 覆盖服务端地址 默认: 使用配置文件 ``` --- ## 安全审计 > 基于《代码审查与优化报告》(md) 与《CODE_AUDIT_REPORT》(docx) 两份审计报告的合并修复结果 ### P0 — 数据正确性与安全(已全部修复) | 编号 | 问题 | 修复方案 | |------|------|---------| | P0-1 | UDP 数据截断丢失尾部 8 字节 | client.rs 读取缓冲区 1400→1392,移除 `n.min(1392)` 截断 | | P0-2 | PacketReader 协议错误断连 | `try_decode()` 遇无效帧头/帧尾返回 `Ok(None)` 跳过,不再 `Err` 断连 | | P0-3 | P2P 隧道时序竞争(目标端先注册,发起端未就绪) | 客户端新增 `pending_p2p_data` 暂存早期数据,注册写半部后刷出 | | P0-4 | Web API 无认证 | 新增 Bearer Token 认证中间件,登录返回 UUID v4 Token | | P0-5 | 端口发布 `try_send` 静默丢数据 | 区分 `Closed`/`Full`,均调用 `active_publish.remove` 清理 | | P0-6 | UDP 中继 TOCTOU + NAT 地址覆盖 + 无法停止 | 全重写 `udp_relay.rs`:单 `get_mut`、`addr_to_session` 反向映射、`watch` 停止、`on_cleanup` 回调 | ### P1 — 服务可靠性(核心已修复) | 编号 | 问题 | 修复方案 | |------|------|---------| | P1-1 | 客户端断连后资源未清理 | 增加 `tunnel_infos`、`port_publishes` 清理 + 调用 `stop_port_publish` | | P1-3 | 蜜罐端口判断逻辑错误 | 移除 `addr.port()` 判断,main.rs 新增蜜罐独立 `accept` 循环 | | P1-4 | TCP 中继缓冲区过小(1470) | 统一改为 8192,常量定义在 `buffer.rs` | | P1-5 | 每个数据包 spawn 新 task | `cmd_p2p_transfer.rs` 改用 `try_send` 非阻塞投递 | | P1-6 | 无法优雅停止 | 保存 `JoinHandle`,新增 Ctrl+C 信号处理 + shutdown channel | ### P2 — 代码质量(核心已修复) | 编号 | 问题 | 修复方案 | |------|------|---------| | P2-1 | `CommandContext` 残留已废弃的 `writer` 字段 | 移除 `writer`、`send_packet`,简化为仅 `client_id` | | P2-2 | 登录响应绕过 mpsc channel 直接锁写 | 改走 `tx.send()` 与后续写入统一路径 | | P2-5 | 日志文件 IO 阻塞 tokio 运行时 | 改用 `spawn_blocking` 异步写入 | | P2-6 | 协议帧 DataLen 无上限 | 新增 `MAX_DATA_LEN`(16MB)检查 | | P2-7 | `save_config` 非原子写入 | 先写 `.tmp` 再 `rename`,防止断电丢配置 | | P2-8 | 缓冲区大小散落各处为魔法数字 | 新建 `buffer.rs` 模块统一常量 | --- ## 致谢 - [Wireboy.Socket.P2PSocket](https://github.com/hemaju/Wireboy.Socket.P2PSocket) — 原始 C# 项目,本项目的协议设计与功能参考来源 ## 许可证 MIT License