# ZNetCore **Repository Path**: sakura1996/znetcore ## Basic Information - **Project Name**: ZNetCore - **Description**: 基于ZReactor的TCP网络库 - **Primary Language**: C++ - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-04 - **Last Updated**: 2026-07-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ZNetCore Linux 上的 **C++20 TCP 网络库**:在 [ZReactor](deps/zreactor/README.md) Reactor 运行时之上,提供 muduo 风格的 `Acceptor`、`Buffer`、`TcpConnection`、`TcpServer`,以及主动建连的 `Connector`、`TcpClient`。参照 [muduo](https://github.com/chenshuo/muduo) 网络层子集实现,分阶段设计文档 + 可运行示例 + 单元测试。 > **定位**:ZReactor 负责 **Reactor 内核**(`EventLoop`、`Channel`、线程池、定时器);**ZNetCore** 负责 **TCP 语义**(监听、accept、连接读写、多 IO 线程派发),把 ZReactor 多线程 Echo 示例里散落在用户代码中的网络逻辑收成库能力。 需求与分阶段计划见 [docs/project-plan.md](docs/project-plan.md);与 ZReactor 的 API 边界见 [deps/zreactor/docs/system-user-boundary.md](deps/zreactor/docs/system-user-boundary.md)。 --- ## 本项目优势 对外 API 对齐 [muduo](https://github.com/chenshuo/muduo) 常用写法(`TcpServer` / `TcpConnection`、回调驱动 echo),差异主要在 **Reactor 怎么分层** 以及 **连接如何安全关闭**。 ### Reactor 与 TCP 双层分离 muduo 把 `EventLoop`、`Channel`、`TcpServer` 放在同一库;ZNetCore 拆为 **ZReactor**(`reactor::`,Submodule)与 **ZNetCore**(`net::`)。Reactor 只管 epoll、定时器、跨线程投递;TCP 的 accept、读写、关闭、多 IO 线程派发收在 `net::`。升级或替换 Reactor 后端时,`TcpServer` / `TcpClient` 的对外接口可保持稳定。 ### 连接续命:回调闭包内传入 `weak_ptr`(对比 muduo `Channel::tie`) muduo 在连接建立时 `channel_->tie(shared_from_this())`,把连接的 `weak_ptr` 存进 `Channel`;此后每次 `handleEvent` 须先 `lock()` 再分发,用栈上 `shared_ptr` 防回调栈内 UAF(关闭流程仍在 `TcpConnection`)。代价是:(1)**Reactor 与上层对象耦合**;(2)**所有**回调共用一次绑定检查;(3)且只能绑**一个**对象。 ZReactor 的 `Channel` 无 `tie()`,只做 fd 分发,框架不关注上层对象生命周期。`TcpConnection` 在各回调闭包内 `weak_ptr::lock()`,每个回调可灵活捕获任意数量的 `weak_ptr` ### 读回调与时间语义上移 muduo 的 Channel 读回调为 `void(Timestamp)`,listen 与连接 fd 同一签名。ZReactor 的 Channel 回调均为 **`void()`**;接收时刻由 `TcpConnection::handleRead` 采集,经 `MessageCallback(conn, buf, receiveTime)` 传给业务。需要算延迟时可对齐 muduo;简单 echo 可忽略第三参数。 ### 现代栈与可学习性 - **C++20**、无 Boost;代码即注释 - 定时器与 `Timestamp` 基于 **steady_clock**,与 `timerfd` 一致。 - **六阶段**递进(Socket → … → TcpClient),每层有独立设计文档与 gtest。 ### 多端口监听 muduo 中 `TcpServer` 与 `Acceptor` 约为 **1:1**;要多端口监听,通常需建多个 `TcpServer`,各自带 `Acceptor` 与 IO 线程池。ZNetCore 在 **单个 `TcpServer` 内组合多个 `Acceptor`**(`vector>`),共享一份 `EventLoopThreadPool` 与 `connections_`、同一套用户回调——`Acceptor` 仍保持单 listen fd 语义,编排归 Server 层。构造可传多个 `InetAddress`,或 `addListen()` 动态增加。见 [feature-tcp-server-multi-listen.md](docs/feature-tcp-server-multi-listen.md)。 | 维度 | muduo | ZNetCore | |------|-------|----------| | 结构 | 一体化 `muduo::net` | `reactor::` + `net::` 两层 | | Channel | `tie` 绑定单对象 + 读回调带时间 | 纯 `void()` 事件;续命在回调闭包内 `weak_ptr` | | 续命 | Channel `tie` + 回调绑 `this` | 回调闭包内 `weak_ptr::lock()`,Channel 无 `tie` | | 多端口 | 多 `TcpServer`(多 pool) | 单 `TcpServer` 多 `Acceptor`(共享 pool 与连接表) | 更多细节:[phase04-design.md §5.7](docs/phase04-design.md)、[system-user-boundary.md](deps/zreactor/docs/system-user-boundary.md)。 --- ## 关键架构 ### 双层栈:应用 → ZNetCore → ZReactor ```text ┌─────────────────────────────────────────────────────────────┐ │ 应用 / 业务(用户) │ │ reactor::EventLoop loop; │ │ net::TcpServer server(loop, addr, name); // 或 TcpClient │ │ setMessageCallback / setConnectionCallback … │ │ server.run(); // 或 client.connect() + loop.loop() │ └───────────────────────────┬─────────────────────────────────┘ │ 公共 API:net:: + 用户持有 reactor::EventLoop ┌───────────────────────────▼─────────────────────────────────┐ │ ZNetCore(本仓库) │ │ TcpServer / TcpClient → TcpConnection → Buffer │ │ Acceptor(服务端) / Connector(客户端) → Socket │ └───────────────────────────┬─────────────────────────────────┘ │ 实现依赖:reactor::(Channel 等不向上暴露) ┌───────────────────────────▼─────────────────────────────────┐ │ ZReactor(deps/zreactor @ 00e5c3e) │ │ EventLoop · Channel · EventLoopThreadPool · Timer … │ └───────────────────────────┬─────────────────────────────────┘ │ epoll / timerfd / eventfd ┌───────────────────────────▼─────────────────────────────────┐ │ Linux 内核 │ └─────────────────────────────────────────────────────────────┘ ``` ### Multi-Reactor:主从 + Round-Robin `TcpServer` 组合 `Acceptor`(baseLoop)与 `EventLoopThreadPool`(Sub Reactors);新连接在 baseLoop 上经 `selectLoop` 选 io 线程,再 `runInLoop(connectEstablished)`。 ```text baseLoop ──Acceptor::accept──► TcpServer::newConnection │ │ │ ▼ selectLoop() └──────── EventLoopThreadPool ──► ioLoop_k::runInLoop(TcpConnection) ``` `threadNum == 0` 时退化为单线程:accept 与连接 I/O 同在 baseLoop(等价于阶段 4 单线程 echo)。 --- ## 技术亮点 | 亮点 | 说明 | |------|------| | **连接生命周期(对比 muduo tie)** | `Channel` 无 `tie`;`weak_ptr` 回调 + `queueInLoop(connectDestroyed)` 延后移除 Channel,Reactor 与 Connection 解耦 | | **读回调(对比 muduo Timestamp)** | `Channel` 回调为 `void()`;`Timestamp` 由 `TcpConnection` 采集后经 `MessageCallback` 可选上送,Reactor 不强制时间语义 | | **用户持有 Main Reactor** | `TcpServer(EventLoop&, …)` 注入 baseLoop;`server.run()` 或 `loop.loop()` 驱动 accept;定时器与 Server 共享同一 `EventLoop` | | **回调驱动业务** | `ConnectionCallback`(Up/Down)+ `MessageCallback`(有数据);框架管 I/O,用户管协议与逻辑 | | **TcpConnection 状态机** | `connecting → connected → disconnecting → disconnected`;`shutdown` 半关闭、`forceClose` 立即 teardown | | **Buffer 读写** | `readFd` / `writev` scatter-gather;`prepend` 便于协议长度字段回填 | | **线程安全 send** | 跨线程 `conn->send()` 内部 `runInLoop` 投递到所属 ioLoop | | **Acceptor EMFILE 防护** | `idleFd_` 预留 fd,进程 fd 耗尽时仍能 accept 并立即关闭,避免 listen backlog 堆积 | --- ## 核心组件 | 组件 | 命名空间 | 职责 | |------|----------|------| | **InetAddress / Socket / sockops** | `net::` | 地址解析、RAII 套接字、syscall 封装 | | **Acceptor** | `net::` | listen fd + `Channel`;可读时 `accept`,经 `NewConnectionCallback` 上报 | | **Buffer** | `net::` | 动态扩容读写缓冲区;`readFd` / `append` / `retrieve` | | **TcpConnection** | `net::` | 单连接 Socket + Channel + 双 Buffer;读写事件、send/shutdown | | **TcpServer** | `net::` | Acceptor + 线程池 + 连接表;新连接派发与用户回调转发;构造注入 `EventLoop&` | | **Connector** | `net::` | 向单一 `serverAddr` 发起非阻塞 `connect`;成功经 `NewConnectionCallback` 交出 fd | | **TcpClient** | `net::` | 聚合 `Connector` + 单条 `TcpConnection`;`connect` / `disconnect` / `stop`;可选断线重连 | 头文件根目录:`include/`(`#include "TcpServer.h"`、`#include "TcpClient.h"`、`#include "netBase/InetAddress.h"`)。 --- ## 最小示例 ```cpp #include "TcpServer.h" #include "EventLoop.h" #include "netBase/InetAddress.h" int main() { reactor::EventLoop loop; net::TcpServer server(loop, net::InetAddress(9983), "EchoServer"); server.setThreadNum(4); server.setMessageCallback([](const net::TcpConnectionPtr& conn, net::Buffer& buf, reactor::Timestamp) { conn->send(buf); }); server.run(); } ``` 多端口:`TcpServer(loop, {net::InetAddress(9983), net::InetAddress(9984)}, "Echo")` 或 `std::vector` 构造,见 [feature-tcp-server-multi-listen.md](docs/feature-tcp-server-multi-listen.md)。 定时器与 `TcpServer` 共享同一 `EventLoop`:`loop.runAfter(...)` 与 `server.start()` 使用同一 `loop` 实例。 完整示例(连接统计、线程 id 后缀)见 [examples/EchoServerMultiThread/EchoServerMultiThread.cpp](examples/EchoServerMultiThread/EchoServerMultiThread.cpp)。 --- ## 依赖关系 | 依赖 | 仓库 | 引入方式 | 固定版本 | |------|------|----------|----------| | **ZReactor** | https://gitee.com/sakura1996/zreactor | Git Submodule(`deps/zreactor/`) | **00e5c3e**(`selectLoop()`;`threadNum==0` 时返回 `baseLoop_`) | ```text ZNetCore (本仓库) └── deps/zreactor/ ← Git Submodule → gitee.com:sakura1996/zreactor @ 00e5c3e └── ZReactor::reactor (CMake 静态库目标) ``` ### 获取源码 ```bash # 推荐:递归克隆(一次性拉取 submodule) git clone --recursive git@gitee.com:sakura1996/znetcore.git # 已克隆主仓库、未拉 submodule 时: git submodule update --init --recursive # 确认 ZReactor 版本 cd deps/zreactor && git describe --tags --always ``` 升级 ZReactor 时,在 `deps/zreactor/` 目录 `git checkout ` 后于仓库根目录 `git add deps/zreactor` 并提交,以固定新的 commit。 --- ## 构建与运行 **依赖**:Linux、CMake ≥ 3.16、**GCC g++ ≥ 13**(使用 `` 等 C++20 特性;顶层构建默认 `g++-13`)。 ```bash cmake -S . -B build cmake --build build ``` 可选目标: ```bash cmake --build build --target EchoServerMultiThread ``` **单元测试**(依赖系统 **GTest 1.14+**,`find_package(GTest 1.14 REQUIRED)`): ```bash # Ubuntu/Debian 示例 sudo apt install libgtest-dev cmake --build build --target TestTcpServer cmake --build build --target TestTcpClient ctest --test-dir build --output-on-failure ``` 关闭示例 / 测试: ```bash cmake -S . -B build -DZNETCORE_BUILD_EXAMPLES=OFF -DZNETCORE_BUILD_TESTS=OFF ``` **多线程 Echo 示例** ```bash # 参数:IO 线程数(默认 4);-port 逗号分隔(默认 9983) ./build/examples/EchoServerMultiThread/EchoServerMultiThread 4 ./build/examples/EchoServerMultiThread/EchoServerMultiThread 4 -port 9983,9984 nc localhost 9983 nc localhost 9984 ``` **性能粗测**(ZReactor `BenchmarkClient` × `EchoServerMultiThread`,1000 连接 × 100 s):本机约 **114 万 msg/s**;复现命令与原始数据见 [docs/benchmark-results.md](docs/benchmark-results.md)。 若 `find_package(GTest 1.14)` 失败,请安装 **1.14** 及以上版本的 GTest(如 `libgtest-dev`),或通过 `CMAKE_PREFIX_PATH` 指向自编译安装前缀。 --- ## 目录结构 ```text ZNetCore/ ├── include/ # 对外头文件(TcpServer、TcpClient、Connector …) │ └── netBase/ # InetAddress、Socket、SockOps … ├── src/ # znetcore 静态库 ├── examples/ # EchoServerMultiThread、EchoClient、联调与压测记录 ├── tests/ # gtest 单元测试(8 套) ├── deps/zreactor/ # ZReactor submodule └── docs/ # 分阶段设计、总纲、压测记录 ``` --- ## 文档 | 文档 | 内容 | |------|------| | [project-plan.md](docs/project-plan.md) | 总纲、需求边界、与 ZReactor 分工、阶段划分 | | [phase01-design.md](docs/phase01-design.md) ~ [phase06-design.md](docs/phase06-design.md) | 各阶段详细设计(phase05 / project-plan 中 TcpServer 构造描述以当前代码为准) | | [phase06-design.md](docs/phase06-design.md) | Connector + TcpClient 架构、与 Server 侧对称关系 | | [feature-tcp-server-multi-listen.md](docs/feature-tcp-server-multi-listen.md) | TcpServer 多端口监听 | | [benchmark-results.md](docs/benchmark-results.md) | EchoServer 本机压测记录 | | [system-user-boundary.md](deps/zreactor/docs/system-user-boundary.md) | 库与应用的 API 边界(以多线程 Echo 为例) | | [submodule-consumption.md](deps/zreactor/docs/submodule-consumption.md) | ZReactor 作为 Submodule 的集成说明 | | [ZReactor README](deps/zreactor/README.md) | Reactor 内核架构与构建 | --- ## 作为依赖(CMake 集成) ```cmake cmake_minimum_required(VERSION 3.16) project(MyApp LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_subdirectory(deps/zreactor) add_subdirectory(deps/znetcore) # 或 add_subdirectory(path/to/ZNetCore) add_executable(my_server main.cpp) target_link_libraries(my_server PRIVATE ZNetCore::znetcore) ``` 头文件约定: - ZNetCore:`#include "TcpServer.h"`、`#include "TcpClient.h"`、`#include "netBase/InetAddress.h"` 等 - Main Reactor:`#include "EventLoop.h"` → `reactor::EventLoop`(由应用创建并传入 `TcpServer` / `TcpClient`) - ZReactor 内部头在 `reactorBase/`,与 `netBase/` 路径对称;`reactor::` 实现细节不通过 `TcpServer` 公共 API 暴露 --- ## 开发说明 顶层构建时生成 `build/compile_commands.json`,可链到仓库根目录供 clangd 使用。若 IDE 仍有误报,执行 **Developer: Reload Window**。 编码规范可参考 ZReactor [docs/coding-style.md](deps/zreactor/docs/coding-style.md)。 --- ## 参与贡献 1. Fork 本仓库 2. 新建功能分支 3. 提交代码(若修改 submodule 指针,请在 commit 中说明 ZReactor 版本) 4. 新建 Pull Request --- ## 许可 [MIT](LICENSE)