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.bat

7.2 方法二:手动编译

mkdir build && cd build
cmake .. -G "Ninja" -DCMAKE_PREFIX_PATH=D:\MSVCQt\6.11.0\msvc2022_64 -DCMAKE_BUILD_TYPE=Release
cmake --build . --parallel

8 使用指南

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