一个用Rust编写的高性能P2P网络握手服务器,采用UDP无连接传输,支持节点发现、消息路由和连接管理。
-
🚀 高性能异步网络处理 - 基于Tokio异步运行时
-
🤝 P2P握手协议 - 完整的节点认证和握手流程
-
🔍 节点发现 - 自动发现和连接网络中的其他节点
-
📡 消息路由 - 智能消息转发和路由机制
-
🔗 连接池管理 - 高效的连接生命周期管理
-
⚙️ 配置文件支持 - 灵活的TOML配置
-
📊 完整日志记录 - 详细的运行状态监控
-
🛡️ 错误处理 - 健壮的错误恢复机制
-
📶 UDP无连接传输 - 更低延迟,更适合P2P场景
-
✅ 可靠性增强 - 支持ACK确认与重传、序列号
-
🧭 地址驱动的对等管理 - 基于
SocketAddr的节点索引
- 🔍 NAT类型检测 - 自动识别完全锥形、受限锥形、端口受限锥形和对称NAT
- 🌐 内置STUN服务器 - 可选的内置STUN服务,支持NAT穿透
- 🔄 流量转发机制 - 为对称NAT客户端提供服务器中继转发
- 🎯 智能端口预测 - 基于历史模式和机器学习的端口预测算法
- 📈 频率调优 - 动态调整连接尝试频率以提高成功率
- 🔒 安全控制 - 可配置的转发权限和速率限制
本项目已从TCP迁移到UDP,核心改动如下:
network.rs:使用UdpSocket实现收发、维护已知对等地址、支持直接send_to与receive_fromprotocol.rs:新增Ack与Retransmit消息类型,消息增加sequence_number与requires_ack/ack_for字段peer.rs:增加基于地址的对等节点索引与查找,适配无连接特性server.rs:主循环由“接受连接”改为“接收数据包”,并在需要时自动回复ACKexamples/simple_client.rs:客户端示例改为UDP实现,演示握手、数据、Ping/Pong与断开
确保你已经安装了Rust(推荐使用最新稳定版):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shgit clone <repository-url>
cd P2P_Handshake_Server
cargo build --release使用默认配置运行:
cargo run --bin p2p_server使用自定义配置:
cargo run --bin p2p_server -- --config config.toml --address 127.0.0.1:8080启用ICE增强功能:
# 启用内置STUN服务器
cargo run --bin p2p_server -- --STUN
# 启用流量转发
cargo run --bin p2p_server -- --relay
# 同时启用STUN和流量转发
cargo run --bin p2p_server -- --STUN --relaycargo run --example simple_client建议优先使用命令行参数设置日志级别(优先级更高):
cargo run --bin p2p_server -- --INFO未指定 CLI 日志级别时,可通过环境变量控制:
export RUST_LOG=info
cargo run --bin p2p_server可用的日志级别:ERROR, WARN, INFO, DEBUG, TRACE
服务器支持通过JSON配置文件进行配置。示例配置文件 config.json:
{
"listen_address": "127.0.0.1:8080",
"max_connections": 100,
"heartbeat_interval": 30,
"connection_timeout": 60,
"discovery_port_range": [8081, 8090],
"enable_discovery": true
}listen_address: 服务器监听地址和端口max_connections: 最大并发连接数heartbeat_interval: 心跳间隔(秒)connection_timeout: 连接超时时间(秒)discovery_port_range: 节点发现端口范围enable_discovery: 是否启用节点发现功能
为了提供更灵活的配置方式,服务器支持通过命令行参数进行配置。这些参数会覆盖配置文件中的相应设置。
--config <PATH>: 指定配置文件的路径。--listen-address <ADDRESS>: 设置服务器监听的IP地址和端口。--max-connections <NUMBER>: 设置最大客户端连接数。--network-id <ID>: 指定P2P网络的唯一标识符。--heartbeat-interval <SECONDS>: 设置心跳消息的发送频率(秒)。--connection-timeout <SECONDS>: 设置连接因不活动而超时的时长(秒)。--enable-discovery <true|false>: 启用或禁用节点发现功能。
# 使用指定的网络ID和监听地址启动服务器
$ cargo run -- --network-id "my-test-network" --listen-address "127.0.0.1:9000"
# 从配置文件加载配置,但覆盖最大连接数
$ cargo run -- --config config.json --max-connections 200p2p_server [OPTIONS]
OPTIONS:
-a, --address <ADDRESS> 服务器监听地址 [default: 127.0.0.1:8080]
-m, --max-connections <NUMBER> 最大连接数 [default: 100]
-c, --config <FILE> 配置文件路径
--TRACE 设置日志级别为 TRACE(与下列日志级别互斥)
--DEBUG 设置日志级别为 DEBUG(互斥)
--INFO 设置日志级别为 INFO(互斥)
--WARN 设置日志级别为 WARN(互斥)
--ERROR 设置日志级别为 ERROR(互斥)
-h, --help 显示帮助信息服务器支持以下消息类型:
HandshakeRequest- 握手请求HandshakeResponse- 握手响应Ping- 心跳包Pong- 心跳响应DiscoveryRequest- 节点发现请求DiscoveryResponse- 节点发现响应Data- 数据传输Error- 错误消息Disconnect- 断开连接Ack- 确认消息(用于提升UDP可靠性)Retransmit- 请求重传(在丢包场景下触发)
所有消息都使用JSON格式,包含以下字段:
{
"id": "uuid",
"message_type": "MessageType",
"timestamp": 1234567890,
"payload": {},
"sequence_number": 1,
"requires_ack": false,
"ack_for": null
}说明:
sequence_number:消息序列号,用于去重与重传识别requires_ack:是否需要ACK确认ack_for:当为ACK消息时,指向被确认消息的序列号
- 客户端使用UDP向服务器发送
HandshakeRequest(可设置requires_ack=true) - 服务器解析请求并返回
HandshakeResponse,同时发送Ack - 客户端收到
HandshakeResponse与Ack后进入认证状态 - 后续数据、Ping/Pong等消息可按需要求ACK;若未确认可触发
Retransmit
src/
├── main.rs # 主程序入口
├── lib.rs # 库入口
├── config.rs # 配置管理
├── network.rs # 网络连接管理
├── peer.rs # 对等节点管理
├── protocol.rs # 通信协议定义
├── router.rs # 消息路由
└── server.rs # 主服务器逻辑
examples/
└── simple_client.rs # 客户端示例
config.json # 示例配置文件
cargo testcargo doc --open在你的 Cargo.toml 中添加依赖:
[dependencies]
p2p_handshake_server = { path = "path/to/P2P_Handshake_Server" }
tokio = { version = "1.0", features = ["full"] }示例代码:
use p2p_handshake_server::{Config, P2PServer};
use std::net::SocketAddr;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 创建配置
let config = Config::new(
"127.0.0.1:8080".parse::<SocketAddr>()?,
50
);
// 创建并启动服务器
let mut server = P2PServer::new(config).await?;
server.run().await?;
Ok(())
}// 主动连接到其他节点
server.connect_to_peer("127.0.0.1:8081".parse()?).await?;let stats = server.get_stats().await;
println!("连接的节点数: {}", stats.peer_stats.total_peers);- 异步I/O: 基于Tokio的高性能异步网络处理
- 零拷贝: 高效的消息序列化和传输
- 连接复用: 智能的连接池管理
- 内存安全: Rust的内存安全保证
- 并发处理: 支持大量并发连接
- 消息大小限制(默认1MB)
- 连接数限制
- 超时机制
以下以本机回环地址为例,带你从零启动并完成一次完整的握手与消息交互。
git clone <repository-url>
cd P2P_Handshake_Server
cargo build --release- 使用默认配置(监听
127.0.0.1:8080,最大连接数 100):
cargo run --bin p2p_server- 指定监听地址与连接数(未提供
--config时生效):
cargo run --bin p2p_server -- --address 127.0.0.1:8080 --max-connections 200- 从配置文件启动(当传入
--config时,配置文件优先于命令行地址与连接数):
cargo run --bin p2p_server -- --config config.jsoncargo run --example simple_client客户端会依次发送握手、数据与 Ping,并打印收到的响应(如 HandshakeResponse 与 Pong)。
- 服务器日志会显示握手、ACK、数据回显以及心跳统计等信息。
- 客户端会打印从服务器接收的各类响应与可能发生的超时提示。
- 传入
--config <file>时:程序从文件加载所有字段(listen_address、max_connections、heartbeat_interval等),这些值在运行期生效。 - 未传入
--config时:使用命令行的--address与--max-connections构建默认配置,其余字段使用代码默认值(心跳 30s、连接超时 60s、发现端口范围8081-8090、启用发现)。
示例配置(config.json):
{
"listen_address": "127.0.0.1:8080",
"max_connections": 100,
"heartbeat_interval": 30,
"connection_timeout": 60,
"discovery_port_range": [8081, 8090],
"enable_discovery": true
}握手请求(带 ACK):
{
"id": "b5e2e2b2-...",
"message_type": "HandshakeRequest",
"timestamp": 1710000000,
"payload": {
"node_id": "client-uuid",
"listen_addr": "127.0.0.1:9000",
"capabilities": ["test"],
"metadata": {"client_type": "udp_test_client"}
},
"sequence_number": 1,
"requires_ack": true,
"ack_for": null
}对应 ACK:
{
"id": "c1f4a8f3-...",
"message_type": "Ack",
"timestamp": 1710000001,
"payload": null,
"sequence_number": 0,
"requires_ack": false,
"ack_for": 1
}数据消息与回显响应:客户端发送 Data,服务器回 {"echo": ..., "timestamp": ...}。
- 建议优先通过命令行参数设置日志级别(如
--INFO、--DEBUG、--TRACE);未指定时可使用环境变量RUST_LOG(支持error | warn | info | debug | trace)。 - 生产运行建议使用
info,调试时使用debug或trace(可能较为冗长)。 - 定期统计输出:服务器每 5 分钟打印对等节点统计(已认证、连接中等)。
- 端口占用:修改
--address端口或更新config.json;在 Windows 上可用netstat -ano | findstr :8080查找占用进程。 - 防火墙拦截:确保操作系统防火墙允许 UDP 入站到监听端口;企业网络可能对广播/发现端口有限制。
- 收不到 ACK:检查网络丢包与
requires_ack设置,必要时调整心跳与超时参数。 - 超时过多:在高丢包网络下,适当加大
connection_timeout与重试策略;关注日志中的 Error 与 Warn。
本仓库的 CI 会为多个平台产出可执行包。你可以在 GitHub 的 Actions 任务详情中下载构建产物(Artifacts),或在打标签(v*)后在 Releases 草稿中下载(路径为 dist/**)。
- Windows:
p2p_server-<target>-windows.zip,解压后得到p2p_server-<target>-windows.exe - Linux:
p2p_server-<target>-linux.tar.gz,解压后得到p2p_server-<target>-linux - macOS:
p2p_server-<target>-macos.tar.gz,解压后得到p2p_server-<target>-macos
示例目标标识:x86_64-pc-windows-msvc、x86_64-unknown-linux-gnu、x86_64-apple-darwin。
# 解压
Expand-Archive -Path p2p_server-x86_64-pc-windows-msvc-windows.zip -DestinationPath .
# 运行(优先从配置文件读取)
./p2p_server-x86_64-pc-windows-msvc-windows.exe --config config.json
# 或使用命令行参数(未提供 --config 时生效)
./p2p_server-x86_64-pc-windows-msvc-windows.exe --address 127.0.0.1:8080 --max-connections 200
# 设置日志级别
# 优先使用 CLI 指定日志级别
./p2p_server-x86_64-unknown-linux-gnu-linux --INFO
# 若未指定 CLI 日志级别,可使用环境变量
RUST_LOG=info ./p2p_server-x86_64-unknown-linux-gnu-linux可选:将可执行文件重命名为 p2p_server.exe 以便调用。
# 解压
tar -xzf p2p_server-x86_64-unknown-linux-gnu-linux.tar.gz
# 赋权(如需)
chmod +x p2p_server-x86_64-unknown-linux-gnu-linux
# 运行
./p2p_server-x86_64-unknown-linux-gnu-linux --config config.json
# 日志级别(优先使用 CLI 指定)
./p2p_server-x86_64-unknown-linux-gnu-linux --INFO
# 若未指定 CLI 日志级别,可使用环境变量
RUST_LOG=info ./p2p_server-x86_64-unknown-linux-gnu-linux# 解压
tar -xzf p2p_server-x86_64-apple-darwin-macos.tar.gz
# 赋权(如需)
chmod +x p2p_server-x86_64-apple-darwin-macos
# 运行
./p2p_server-x86_64-apple-darwin-macos --config config.json
# 日志级别(优先使用 CLI 指定)
./p2p_server-x86_64-apple-darwin-macos --INFO
# 若未指定 CLI 日志级别,可使用环境变量
RUST_LOG=info ./p2p_server-x86_64-apple-darwin-macos--config <file>:从文件加载所有配置(优先级最高)。- 未提供
--config时,命令行的--address与--max-connections生效,其余字段使用默认值(心跳 30s、超时 60s、发现端口范围8081-8090、启用发现)。
- Release 任务会在
dist/SHA256SUMS.txt中生成校验文件。 - Linux/macOS 校验:
sha256sum <artifact>;Windows 校验:certutil -hashfile <artifact> SHA256。 - 构建发布为草稿(
draft: true),可在 GitHub 上确认后正式发布。
- 构建产物仅包含服务器二进制;示例客户端不打包。如需联调,请在源码仓库运行:
cargo run --example simple_client。 - Windows 可能需要在防火墙中放行入站 UDP;Linux/macOS 需确认端口未被占用。
- 使用
cargo build --release构建并运行,以获得更佳性能。 - 将配置与日志级别分离至环境与文件,避免硬编码。
- 监控与滚动重启:结合系统服务或进程管理器(如 systemd、NSSM)进行守护与重启。
-
中文文档:
README/overview.md(总体架构)README/protocol.md(协议说明)README/discovery.md(节点发现)README/routing.md(消息路由)README/server.md(服务器实现)README/client.md(客户端示例)
-
English Docs:
README-EN/overview.mdREADME-EN/protocol.mdREADME-EN/discovery.mdREADME-EN/routing.mdREADME-EN/server.mdREADME-EN/client.md
-
错误恢复
-
资源清理
-
更新日志:
CHANGELOG.md(包含版本历史与变更说明)
-
端口被占用
Error: 绑定地址 127.0.0.1:8080 失败解决方案:更改监听端口或停止占用端口的程序
-
连接超时
Error: 连接到 x.x.x.x:xxxx 失败解决方案:检查网络连接和目标地址是否正确
-
握手失败
Error: 握手失败: 节点ID xxx 已存在解决方案:确保每个节点使用唯一的ID
-
接收UDP数据失败
ERROR p2p_server::server] 接收UDP数据包失败: 接收UDP数据失败说明:常见于客户端断开后,服务器仍在接收循环中;不影响整体功能。可通过降低日志级别或在接收失败处放宽日志级别进行优化。
- 不再建立
TcpStream连接,改为使用UdpSocket的send_to/recv_from - 增加ACK与重传机制以提升可靠性(
Ack/Retransmit,requires_ack与sequence_number) - 节点管理依赖
SocketAddr,同一地址即同一对等节点 - 主动连接改为发送握手请求包(
connect_to_peer内部直接发送HandshakeRequest) - 客户端在示例中展示:握手→发送数据→Ping/Pong→断开
设置环境变量来控制日志级别:
export RUST_LOG=info
cargo run --bin p2p_server可用的日志级别:error, warn, info, debug, trace
- ICE增强功能详细说明 - 详细的NAT穿透和流量转发功能文档
- 配置文件示例 - 完整的配置文件示例,包含所有可用选项
本项目采用MIT许可证。 export RUST_LOG=debug cargo run --bin p2p_server
可用的日志级别:`error`, `warn`, `info`, `debug`, `trace`
## 贡献
欢迎提交Issue和Pull Request!
## 许可证
本项目采用MIT许可证。详见 [LICENSE](LICENSE) 文件。