C++项目:仿muduo库高并发服务器---------LoopThreadPool模块和TcpServer模块的实现


文章目录


前言

本篇文章介绍了LoopThreadPool模块和TcpServer模块的实现其中: LoopThreadPool 模块是用来管理 LoopThread而设计的,帮助我们给新建立的连接进行线程分配。TcpServer 模块用于整合所有相关模块,通过实例化该模块的对象,可简便搭建服务器。


一、LoopThreadPool模块设计

1.1 功能概述

LoopThreadPool 用于管理和分配所有 LoopThread,支持可配置的线程数量 (包括 0 个或多个),并能依据主从 Reactor 模型的逻辑,为新连接分配合适的线程(LoopThread 对应的 EventLoop)以进行事件监控与处理。

  1. 线程数量可配置
    线程池能设置包含 0 个或多个 LoopThread。当从属线程数量为 0 时,实现单 Reactor 服务器:一个线程既负责获取新连接,也负责连接的事件处理。

在一些轻量级场景下,一般不需要多线程执行任务

  1. 管理 LoopThread 对象
    对 0 个或多个 LoopThread 实例进行统一管理,包括创建、维护等操作。
  2. 线程分配功能
    • 当主线程获取新连接后,需将其分配给对应线程的 EventLoop 以进行事件监控和处理。
    • 若从属线程数量为 0,直接将新连接分配给主线程的 EventLoop 处理。
    • 若存在多个从属线程,采用 RR(Round - Robin,轮转) 算法进行线程分配:轮询获取从属线程的 EventLoop,并设置到对应的 Connection 中。

1.2 代码实现

cpp 复制代码
class LoopEventPool{
    public:
    LoopEventPool(EventLoop*loop):_base_loop(loop),_next_index(0),_thread_count(0){}
    //设置线程个数
    void SetThreadCount(int sz){
        _thread_count=sz;
    }
    //创建从属线程
    void Create(){
        if(_thread_count>0){
            _threads.resize(_thread_count);
            _loops.resize(_thread_count);
            for(int i=0;i<_thread_count;i++){
                _threads[i]=new LoopServer();
                _loops[i]=_threads[i]->GetEventLoop();
            }
        }
        return;
    }
    //给新到来的连接获取loop
    EventLoop* NextLoop(){
        if(_thread_count==0){
            return _base_loop;
        }
        _next_index=(_next_index+1)%_thread_count;
        return _loops[_next_index];
    }
    private:
    int _thread_count;//创建从属线程线程个数
    int _next_index;//分配线程索引
    EventLoop* _base_loop;//主线程绑定的loop
    std::vector<LoopServer*> _threads;//丛属线程
    std::vector<EventLoop*> _loops;//从属线程对应的loop
};

二、TcpServer模块设计

2.1 模块组成

  1. Acceptor 对象:用于创建监听套接字。
  2. EventLoop 对象(baseloop):实现对监听套接字的事件监控。
  3. std::unordered_map<uint64_t, PtrConnection> _conns:对所有新建连接进行管理。
  4. LoopThreadPool 对象:创建线程池,对新建连接进行事件监控及处理。

2.2 功能概述

  1. 设置从属线程池数量。
  2. 启动服务器。
  3. 设置多种回调函数(连接建立完成、消息、关闭、任意等),用户设置给 TcpServerTcpServer 再设置给获取的新连接。
  4. 选择是否启动非活跃连接超时销毁功能。
  5. 具备添加定时任务功能。

2.3 流程

  1. TcpServer 中实例化 Acceptor 对象和 EventLoop 对象(baseloop)。
  2. Acceptor 挂到 baseloop 上进行事件监控。
  3. Acceptor 对象就绪可读事件时,执行读事件回调函数获取新建连接。
  4. 对新连接,创建 Connection 进行管理。
  5. 对连接对应的 Connection 设置功能回调(连接完成回调、消息回调、关闭回调、任意事件回调)。
  6. 启动 Connection 的非活跃连接的超时销毁规则。
  7. 将新连接对应的 Connection 挂到 LoopThreadPool 中的从属线程对应的 EventLoop 中进行事件监控。
  8. 一旦 Connection 对应的连接就绪了可读事件,则执行读事件回调函数,读取数据,读取完毕后调用 TcpServer 设置的消息回调。

2.4 代码实现

cpp 复制代码
//对所有模块管理、快速搭建服务区
class TcpServer{
        //由组件使用者设置的事件回调
    using Functor=std::function<void()>;
    using ConnectedCallback=std::function<void(PtrConnection)>;
    using MessageCallback=std::function<void(PtrConnection,Buffer*buf)>;
    using ClosedCallback=std::function<void(PtrConnection)>;
    using AnyEventCallback=std::function<void(PtrConnection)>;
    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    AnyEventCallback _event_callback;
    ClosedCallback _server_closed_callback;
private:
    //为线连接创建Connection对象
    void NewConnection(int newfd){
        _next_id++;
        PtrConnection conn(new Connection(_threadpool.NextLoop(), _next_id, newfd));
        conn->SetMessageCallback(_message_callback);
        // conn->SetAnyEventCallback(std::bind(HandleRead));
        conn->SetConnectedCallback(_connected_callback);
        conn->SetClosedCallback(_closed_callback);
        conn->SetAnyEventCallback(_event_callback);
        //内部设置的清理连接信息回调
        conn->SetSrvClosedCallback(std::bind(&TcpServer::RemoveConnection,this,std::placeholders::_1));
        _conns.insert({_next_id, conn});
        if(_enable_inactive_release)
        conn->EnableInactiveRelease(_timeout);
        conn->Established();
        DBG_LOG("NEW LINK THREAD");
    }
    //将连接信息从_conns中移除
    void RemoveConnection(const PtrConnection& conn){
        _baseloop.RunInLoop(std::bind(&TcpServer::RemoveConnectionInLooop,this,conn));
    }
    void RemoveConnectionInLooop(const PtrConnection& conn){
        uint64_t id=conn->Id();
        auto it=_conns.find(id);
        if(it!=_conns.end()){
            _conns.erase(id);
        }
    }
    void RunAfterInLoop(const Functor&task,int dalay){
        _next_id++;
        _baseloop.TimerAdd(_next_id,dalay,task);
    }
public:
    TcpServer(int port)
    :_next_id(0)
    ,_port(port)
    ,_enable_inactive_release(false)
    ,_acceptor(&_baseloop,port)
    ,_threadpool(&_baseloop){
        _acceptor.SetAcceptCallback(std::bind(&TcpServer::NewConnection,this,std::placeholders::_1));
    }
    //设置从属线程个数
    void SetThreadCount(int sz){
        _threadpool.SetThreadCount(sz);
    }
    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 SetSrvClosedCallback(const ClosedCallback&cb) { 
        _server_closed_callback = cb; 
    }
    //启动非活跃销毁
    void EnableInactiveRelease(int timeout){
        _timeout=timeout;
        _enable_inactive_release=true;
    }
    //添加定时任务
    void RunAfter(const Functor&task,int dalay){
        _baseloop.RunInLoop(std::bind(&TcpServer::RunAfterInLoop,this,task,dalay));
    }
    void Start(){
        //创建从属线程
        _threadpool.Create();//创建从属线程
        _acceptor.Listen();//开始监听套接字
        std::cout<<"1"<<std::endl;
        _baseloop.Start();//开始监听处理事件
    }
private:
    uint64_t _next_id;//自增长的线程id;
    int _port;//监听套接字绑定的端口号
    int _timeout;//非活跃连接的超时时间
    bool _enable_inactive_release;//是否启用非活跃连接
    EventLoop _baseloop;//对监听套接字进行事件监控
    Acceptor _acceptor;//创建并管理监听套接字
    LoopEventPool _threadpool;//对从属线程进行管理
    std::unordered_map<uint64_t,PtrConnection> _conns;//存储连接信息

};
相关推荐
getapi21 分钟前
注塑件的费用构成
linux·服务器·ubuntu
Maynor9961 小时前
OpenClaw 玩家必备:用 AI 自动追踪社区最新动态
java·服务器·人工智能
郝学胜-神的一滴1 小时前
深入解析C/S模型下的TCP通信流程:从握手到挥手的技术之旅
linux·服务器·c语言·网络·网络协议·tcp/ip
chian-ocean1 小时前
CANN 生态进阶:利用 `profiling-tools` 优化模型性能
数据库·mysql
“αβ”1 小时前
数据链路层协议 -- 以太网协议与ARP协议
服务器·网络·网络协议·以太网·数据链路层·arp·mac地址
释怀不想释怀1 小时前
Linux网络基础(ip,域名)
linux·网络·tcp/ip
初願致夕霞1 小时前
Linux_进程
linux·c++
开开心心就好1 小时前
AI人声伴奏分离工具,离线提取伴奏K歌用
java·linux·开发语言·网络·人工智能·电脑·blender
lucky-billy2 小时前
Ubuntu 下一键部署 ROS2
linux·ubuntu·ros2
Thera7772 小时前
【Linux C++】彻底解决僵尸进程:waitpid(WNOHANG) 与 SA_NOCLDWAIT
linux·服务器·c++