P2P Text Share (P2P 文字分享箱)
Qt6 C++ — 无中心服务器 P2P 文字即时聊天系统
同一密码即可进入同一房间,局域网自动 UDP 发现,TCP 直连通信,Gossip 协议全连接,历史消息同步,内置信令服务器 + 多服务器联邦互通。
1 项目概览
纯文字即时聊天工具,完全去中心化 — 无需任何中心服务器即可通信。用户只需输入相同的密码,即可自动发现同一局域网内的其他用户,建立全连接对等网络,实现实时文字聊天。
| 语言 | C++17 |
| GUI 框架 | Qt 6.11 (Widgets) |
| 网络层 | Qt Network (QUdpSocket / QTcpSocket / QTcpServer) |
| 构建系统 | CMake + Ninja |
| 编译器 | MSVC 2022 (v143, x64) |
| 平台 | Windows |
| 代码规模 | ~1800 行 (7 个文件) |
| 模式 | 客户端 (P2P) + 信令服务器 (HTTP) + 联邦 (多服务器互通) |
| 许可证 | MIT |
2 功能特性
2.1 客户端
- 无中心 P2P,无需任何中间服务器即可通信
- 密码即房间:SHA-256(password) 前 16 位 hex 作为房间 ID
- 局域网自动发现:UDP 广播 (端口 45454),3 秒心跳
- 手动 IP 连接:支持输入 IP:端口 连接跨网络节点
- 实时聊天:消息通过 TCP 广播到所有节点
- 历史同步与去重:新节点加入自动获取完整聊天记录
- 在线成员列表:右侧面板实时显示
- 调试信息面板:18 种事件类型实时日志,每秒刷新统计
- 日志保存:复选框一键保存,文件名含日期+房间+用户+随机串
- 淡绿色主题
2.2 信令服务器
服务器已内置在客户端中
- HTTP REST API:/register, /unregister, /peers, /stats
- 服务器密码认证,控制 API 访问权限
- 最大用户限制,可配置
- 节点自动过期:45 秒心跳超时自动清理
- 服务器日志面板,实时显示注册/注销/请求事件
- 服务器日志保存,独立于客户端日志
2.2.1联邦 (多服务器互通)
- 三步握手协议:A 请求 → B 弹窗确认 → 双方交换密码
- 双向密码交换,联邦 API 通过 X-Server-Pw header 认证
- 每 8 秒自动 push/pull 节点信息
- 三层传播:接收节点自动转发给其他联邦服务器
- 双方可解除:右键菜单解除联邦,同时通知对方
- 联邦状态显示:绿色=已连接,橙色=等待确认
3 技术栈
| 语言 | C++17 |
| GUI | Qt 6.11 Widgets |
| P2P 网络 | QUdpSocket, QTcpServer, QTcpSocket |
| HTTP 网络 | QTcpServer + QNetworkAccessManager |
| 序列化 | QJsonDocument / QJsonObject / QJsonArray |
| 加密 | QCryptographicHash (SHA-256) |
| ID 生成 | QUuid |
| 线程安全 | QMutex / QMutexLocker |
| 构建 | CMake 3.16+ + Ninja |
| 编译 | MSVC 2022 (v143) x64 |
| 异步 I/O | Qt Signals & Slots,事件驱动,非阻塞 |
4 架构原理
4.1 整体架构
- 客户端之间通过 UDP 广播发现,TCP 直连通信
- 信令服务器 (可选) 存储节点 IP:端口,帮助跨网节点互相发现
- 多个信令服务器通过联邦协议交换节点,实现跨区域互联
- 数据始终 P2P 直连,服务器只存储 IP:端口,不中转通信数据
Node A ←── TCP P2P ──→ Node B ←── TCP P2P ──→ Node C
↕ UDP: hello (255.255.255.255:45454) 局域网发现
Server A (公网 :58080) ←── 联邦互通 ──→ Server B (公网 :58081)
↑ HTTP /register ↑ HTTP /register
↑ GET /peers ↑ GET /peers
Client D (跨网) Client E (跨网)
4.2 UDP 协议层
加入时 3 次连续广播 (间隔 300ms)。
- QUdpSocket::ShareAddress | ReuseAddressHint 允许同机多实例共享端口
- m_pendingConnects 集合防止重复拨号
- 过滤自己的消息和不同房间的消息
4.3 TCP 通信层
二进制协议[4 字节大端长度前缀] [JSON 负载]
消息类型:
| 类型 | 方向 | 内容 |
| hello | UDP 广播 | room, node, tcp_port, name |
| bye | UDP 广播 | room, node |
| intro | TCP | node, name, tcp_port, peers (已知节点列表) |
| intro_ack | TCP | 同 intro,双向握手确认 |
| history | TCP | messages (完整历史) |
| msg | TCP | text, node, name, time, id (唯一消息) |
连接建立流程:
1. A 发起 TCP 连接 B
2. A 发送 intro (自我介绍 + 已知的 peers 列表)
3. B 注册 A 为 peer,推送 history + 系统消息
4. B 回复 intro_ack (自我介绍 + 已知的 peers 列表)
5. A 注册 B 为 peer
6. 双方各自通过 gossip 连接对方介绍的未知节点
4.4 Gossip 全连接协议
每个 intro/intro_ack 携带发送者已知的所有节点列表。接收方遍历列表,对未知节点自动发起 TCP 连接。只需 1 次 UDP 命中即可建立全连接。
4.5 历史同步与去重
- 每条消息带唯一 ID (uuid.hex[:12] 或确定性 join-{node}-{分钟})
- m_historyIds (QSet) 去重
- 新人加入时老节点推送完整历史
- 多个老节点同时推送 → 接收端按 ID 去重,只渲染一份
4.6 信令服务器 (HTTP API)
通过QTcpServer 解析 HTTP 请求实现。
POST /register {room, node, name, port, server_pw} → {ok, error}
POST /unregister {room, node} → {ok}
GET /peers ?room=X&node=Y → {ok, peers}
GET /stats → {rooms, nodes, fed_peers}
POST /fed_request {from_url, my_password} → {ok} 联邦请求
POST /fed_accept {from_url, my_password} → {ok} 联邦接受
POST /fed_remove {from_port} → {ok} 联邦解除
POST /federate_peers {server_port, peers} auth: X-Server-Pw → {ok} 推送节点
GET /federated_peers ?from=PORT auth: X-Server-Pw → {ok, peers} 拉取节点
4.7 联邦架构
三步握手:
1. A 向 B 发 POST /fed_request (携带 A 的密码和 B 的密码)
2. B 弹窗确认 → POST /fed_accept 通知 A (携带 B 的密码)
3. 双方各存对方密码,启动 8s 定时器互推/互拉节点
双向可解除:右键列表中的联邦服务器 → 解除 → POST /fed_remove → 对方自动移除。
4.8 线程模型
借助 Qt6 异步 I/O,不阻塞事件循环。
| 组件 | 机制 |
| UDP 接收 | QUdpSocket::readyRead 信号 |
| TCP 接收 | QTcpSocket::readyRead 信号 |
| TCP 服务器 | QTcpServer::newConnection 信号 |
| TCP 发送 | QTcpSocket::write() + flush() |
| HTTP 请求 | QNetworkAccessManager 异步 |
| 定时广播 | QTimer::timeout 信号 |
| 互斥 | QMutex + QMutexLocker |
5 项目结构
p2p/
├── CMakeLists.txt CMake 构建配置
├── build.bat 一键编译脚本
├── README.md 文档
├── main.cpp 应用入口
├── mainwindow.h 主窗口
├── mainwindow.cpp 主窗口实现
├── network.h P2PNetwork
└── network.cpp 网络核心实现
| CMakeLists.txt | 21 | 构建配置 |
| main.cpp | 21 | 入口 |
| mainwindow.h | 125 | 类声明 |
| mainwindow.cpp | 513 | 双 Tab UI + 全部信号槽 + 双日志 |
| network.h | 203 | P2PNetwork + SignalingServer 声明 |
| network.cpp | 886 | UDP/TCP/Gossip/History/HTTP/联邦 |
| 合计 | ~1769行 | |
6 环境准备
6.1 安装 Visual Studio 2022
1. 访问 https://visualstudio.microsoft.com/zh-hans/downloads/
2. 下载 Visual Studio 2022 Community
3. 安装时勾选 "使用 C++ 的桌面开发" 工作负载
4. 确保安装 MSVC v143 编译工具和 Windows 10/11 SDK
6.2 安装 Qt 6
1. 访问 https://www.qt.io/download-qt-installer
2. 下载 Qt Online Installer
3. 选择组件:Qt 6.11.0 → MSVC 2022 64-bit,勾选 Qt Network;Developer Tools → CMake + Ninja
4. 安装路径建议:D:\MSVCQt
7 编译运行
7.1 方法一:build.bat (推荐)
从普通 cmd.exe运行:
cd /d C:\Users\liyim_uijezlt\Desktop\play\p2pFileProve
build.bat7.2 方法二:手动编译
mkdir build && cd build
cmake .. -G "Ninja" -DCMAKE_PREFIX_PATH=D:\MSVCQt\6.11.0\msvc2022_64 -DCMAKE_BUILD_TYPE=Release
cmake --build . --parallel8 使用指南
8.1 客户端
- 加入房间:点击 "加入房间" → 输入昵称和密码 → 加入。其他用户相同密码即可同房间
- 聊天:底部输入框输入,Enter 或点 "发送"。自己消息绿色,他人蓝色,系统灰色
- 手动连接:点击 "手动连接" → 输入 IP:端口
- 调试面板:右侧实时显示网络事件 + 统计
- 日志保存:勾选复选框 → logs/ 目录
8.2 信令服务器
- 启动:切换到 "信令服务器" Tab → 设置端口/最大用户/密码 → 点击 "启动"
- 联邦:在 "联邦服务器" 输入对方 URL → 点击 "发送请求" → 输入对方密码 → 对方弹窗确认
- 解除:右键联邦列表中的服务器 → "解除联邦连接"
-注意:信令服务器需要拥有公网IP
9 下载项目
项目下载地址:
file store:https://file.candywind.com/@s/ZNjqY94q 分享吗:Scv3V
release下载地址:https://file.candywind.com/@s/bwMx4rRz
仅供学习使用!!!个人及组织禁止分发,下载的文件请在24小时内删除!!!
Made with Qt6 + MSVC 2022
使用p2p搭建文字共享服务器
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法