跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C++ 仿 muduo 库高并发服务器 TcpServer 模块实现

C++ 仿 muduo 库高并发服务器 TcpServer 模块实现。该模块封装了 Acceptor 监听器与 EventLoop 线程池,负责新连接的接受、分发及管理。核心功能包括设置 IO 线程数量、注册连接/消息/关闭等回调函数、启用非活跃连接超时销毁以及添加定时任务。通过主 Reactor 与从 Reactor 模式,利用智能指针管理连接生命周期,确保多线程环境下的线程安全与资源有效释放。

PhpPioneer发布于 2026/2/7更新于 2026/9/3079 浏览
C++ 仿 muduo 库高并发服务器 TcpServer 模块实现

TcpServer 模块介绍

功能概述
  1. 设置从属线程池数量。
  2. 启动服务器。
  3. 设置多种回调函数(连接建立完成、消息、关闭、任意等),用户设置给 TcpServer,TcpServer 再设置给获取的新连接。
  4. 选择是否启动非活跃连接超时销毁功能。
  5. 具备添加定时任务功能。
流程
  1. 在 TcpServer 中实例化 Acceptor 对象和 EventLoop 对象(baseloop)。
  2. 将 Acceptor 挂到 baseloop 上进行事件监控。
  3. 当 Acceptor 对象就绪可读事件时,执行读事件回调函数获取新建连接。
  4. 对新连接,创建 Connection 进行管理。
  5. 对连接对应的 Connection 设置功能回调(连接完成回调、消息回调、关闭回调、任意事件回调)。
  6. 启动 Connection 的非活跃连接的超时销毁规则。
  7. 将新连接对应的 Connection 挂到 LoopThreadPool 中的从属线程对应的 EventLoop 中进行事件监控。
  8. 一旦 Connection 对应的连接就绪了可读事件,则执行读事件回调函数,读取数据,读取完毕后调用 TcpServer 设置的消息回调。
成员介绍

成员变量

uint64_t _next_id

  • 作用:这是一个全局自增的计数器。
  • 用途:每当有一个新连接到来时,_next_id 会加 1,作为这个新连接的唯一 ID (conn_id)。这用于在 _conns 哈希表中唯一标识和查找连接。

int _port

  • 作用:服务器监听的端口号。

int _timeout

  • 作用:非活跃连接的超时时间(单位:秒)。
  • 用途:如果启用了非活跃销毁功能,当连接在 _timeout 秒内没有任何读写事件发生时,服务器会自动断开该连接。

bool _enable_inactive_release

  • 作用:功能开关。
  • 用途:标记是否开启了'非活跃连接自动销毁'功能。

EventLoop _baseloop

  • 作用:主 Reactor(Main Loop)。
  • 用途:这是运行在主线程中的事件循环。它只负责一件事情:监听监听套接字(ListenFd)的事件,也就是处理新用户的连接请求。一旦接受连接,它就会把新连接分发给线程池中的从 Reactor。

Acceptor _acceptor

  • 作用:连接接受器。
  • 用途:它内部封装了监听 Socket。它运行在 _baseloop 中,当有新连接到来时,它会执行 accept 系统调用拿到文件描述符,然后调用 TcpServer::NewConnection 回调函数。

LoopThreadPool _pool
  • 作用:从 Reactor 线程池(Sub Loops)。
  • 用途:管理一组 IO 线程,每个线程运行一个 EventLoop。当 _baseloop 接收到新连接后,会通过 _pool 选择一个 IO 线程,将新连接交给它管理。

std::unordered_map<uint64_t, PtrConnection> _conns

  • 作用:连接容器。
  • 用途:保存服务器当前所有活跃连接的智能指针 (shared_ptr)。
  • 关键点:这是服务器持有连接生命周期的地方。只要连接在这个 map 中,它的引用计数就不为 0,就不会被析构。当连接关闭时,从这里移除,引用计数归零,连接自动销毁。

回调函数对象 (_connected_callback, _message_callback, _closed_callback, _event_callback)

  • 作用:保存用户注册的业务逻辑。
  • 用途:当新连接创建时,这些回调会被传递给 Connection 对象。

成员函数

void NewConnection(int fd)

  • 触发时机:当 Acceptor 检测到新连接请求并成功执行 accept 后调用。
  • 逻辑流程:
    1. _next_id++:生成新连接 ID。
    2. _pool.NextLoop():从线程池中轮询选出一个 EventLoop(负载均衡)。
    3. new Connection(...):创建新连接对象,绑定到选定的 Loop 和 fd 上。
    4. 配置连接:将用户设置的各种回调函数(OnMessage, OnClose 等)传递给这个新连接。
    5. 设置内部关闭回调:这是关键一步,当连接断开时,Connection 对象会回调这个函数,通知 TcpServer 从 _conns 中移除自己。
    6. 启动超时销毁:如果 _enable_inactive_release 为真,开启连接的定时器。
    7. 初始化:调用 conn->Established(),正式开启读事件监控。
    8. 存储:_conns.insert(...),将连接放入 map 中管理。

void RemoveConnection(const PtrConnection& conn)

  • 触发时机:当 Connection 检测到连接断开(对端关闭或错误)并执行清理流程时调用。
  • 作用:它只是一个跳板,为了线程安全,它调用 _baseloop.RunInLoop 将实际的删除操作调度到主线程执行。

void RemoveConnectionInLoop(const PtrConnection& conn)

  • 执行环境:主线程 (_baseloop)。
  • 逻辑:根据连接 ID 从 _conns map 中删除对应的 Connection 对象。
  • 结果:shared_ptr 引用计数减 1。如果此时没有其他地方引用该连接(通常情况),连接对象就会被析构,从而释放 Socket 资源。

void RunAfterInLoop(const Functor task, int delay)

  • 作用:在主循环中添加定时任务的辅助函数。

TcpServer(int port)

  • 构造函数:
    1. 初始化端口。
    2. 初始化 _acceptor,传入 _baseloop 和端口。
    3. 初始化 _pool,传入 _baseloop。
    4. 关键绑定:_acceptor.SetAcceptCallback(...),将 TcpServer::NewConnection 绑定为接受连接的回调。
    5. _acceptor.Listen():立即开始监听端口(此时还没有开始事件循环)

void SetThreadCount(int count)

  • 作用:设置 IO 线程的数量。
  • 说明:
    • count = 0:单线程模式。所有连接的 IO 操作都在主线程 (_baseloop) 中处理。
    • count > 0:多线程模式。主线程只负责 Accept,count 个子线程负责处理连接 IO。

void Start()

  • 作用:启动服务器。
  • 逻辑:
    1. _pool.Create():创建并启动所有 IO 线程。
    2. _baseloop.Start():主线程开始进入 epoll_wait 事件循环,正式开始工作。这是一个死循环,函数调用后不会返回。
源代码
class TcpServer {
private:
    uint64_t _next_id; // 自动增长的连接 ID
    int _port;
    int _timeout; // 超时时间
    bool _enable_inactive_release; // 是否启用非活跃销毁
    EventLoop _baseloop; // 主线程的 EventLoop 对象,负责监听事件的处理
    Acceptor _acceptor; // 监听套接字管理对象
    LoopThreadPool _pool; // 从属 EventLoop 线程池
    std::unordered_map<uint64_t, PtrConnection> _conns; // 保存管理所有连接对应的 shared_ptr 对象

private:
    using ConnectedCallback = std::function<void(const PtrConnection&)>;
    using MessageCallback = std::function<void(const PtrConnection&, Buffer*)>;
    using ClosedCallback = std::function<void(const PtrConnection&)>;
    using AnyEventCallback = std::function<void(const PtrConnection&)>;
    using Functor = std::function<void()>;

    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    AnyEventCallback _event_callback;

    // 为新连接构造一个 Connnection 进行管理
    void NewConnection(int fd) {
        _next_id++;
        PtrConnection conn(new Connection(_pool.NextLoop(), _next_id, fd));
        conn->SetMessageCallback(_message_callback);
        conn->SetClosedCallback(_closed_callback);
        conn->SetConnectedCallback(_connected_callback);
        conn->SetAnyEventCallback(_event_callback);
        conn->SetSrvClosedCallback(std::bind(&TcpServer::RemoveConnection, this, conn));
        if (_enable_inactive_release) conn->EnableInactiveRelease(_timeout); // 启动非活跃超时销毁
        conn->Established(); // 就绪初始化
        _conns.insert(std::make_pair(_next_id, conn));
    }

    void RemoveConnectionInLoop(const PtrConnection& conn) {
        uint64_t id = conn->Id();
        auto it = _conns.find(id);
        if (it != _conns.end()) {
            _conns.erase(it);
        }
    }

    // 从_conns 中移除连接信息
    void RemoveConnection(const PtrConnection& conn) {
        _baseloop.RunInLoop(std::bind(&TcpServer::RemoveConnectionInLoop, this, conn));
    }

    void RunAfterInLoop(const Functor task, int delay) {
        _next_id++;
        _baseloop.TimerAdd(_next_id, delay, task);
    }

public:
    TcpServer(int port) : _port(port), _next_id(0), _enable_inactive_release(false), _acceptor(&_baseloop, port), _pool(&_baseloop) {
        _acceptor.SetAcceptCallback(std::bind(&TcpServer::NewConnection, this, std::placeholders::_1));
        _acceptor.Listen(); // 将监听套接字挂在 baseloop 上
    }

    // 设置线程池数量
    void SetThreadCount(int count) {
        _pool.SetThreadCount(count);
    }

    void SetConnectedCallback(const ConnectedCallback& cb) {
        _connected_callback = cb;
    }

    void SetMessageCallback(const MessageCallback& cb) {
        _message_callback = cb;
    }

    void SetClosedCallback(const ClosedCallback& cb) {
        _closed_callback = cb;
    }

    void SetAnyEventCallback(const AnyEventCallback& cb) {
        _event_callback = cb;
    }

    // 添加定时任务
    void RunAfter(const Functor task, int delay) {
        _baseloop.RunInLoop(std::bind(&TcpServer::RunAfterInLoop, this, task, delay));
    }

    // 启动非活跃销毁
    void EnableInactiveRelease(int timeout) {
        _timeout = timeout;
        _enable_inactive_release = true;
    }

    void Start() {
        _pool.Create();
        _baseloop.Start();
    }
};

目录

  1. TcpServer 模块介绍
  2. 功能概述
  3. 流程
  4. 成员介绍
  5. 源代码

更多推荐文章

查看全部
  • 前端 pnpm workspace 架构详解
  • Ψ0 人形全身 VLA 解析:人类视频预训练与 MM-DiT 后训练策略
  • 详解 Java 中的 @Schema 注解
  • OpenSC2K 开源模拟城市 2000 重制版运行指南
  • HiDream-I1 开源:消费级显卡运行 17B 文生图模型实战
  • 知网 AIGC 检测更新应对:论文降重技巧与工具实测
  • 基于原生 Web 技术实现网页版井字棋游戏
  • Web 应用全栈开发实践:从前端到后端
  • IoT DevOps 实战:基于设备影子的万级电梯网关集群自动化运维架构
  • 文心一言:百度 AI 战略核心与国产大模型实战指南
  • Python 股票数据分析系统搭建指南
  • 机器人系统架构详解:2026 年最新技术路线
  • 《Agent Runtime 工程化》第二章 TypeScript / Node Runtime 基础:2.4 子进程执行器:Agent 的危险地带
  • JavaSE 封装详解
  • 2026 年 3 月全球大模型全景:国产登顶、百万上下文与智能体爆发
  • C++ STL 容器详解:map 与 set 核心用法与底层逻辑
  • 基于 FPGA 的 TDC 抖动测试系统设计与实现
  • Vivado 许可证获取与配置指南
  • simplify-js:高性能多边形简化 JavaScript 算法库实用指南
  • 前端实战:520 表白信封动画效果实现

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online