C++仿muduo库高并发服务器项目:Poller模块

前言

本篇文章所讲的是本人的个人项目仿muduo库高并发服务器中的Poller模块实现部分。

Poller模块介绍:

这也是一个比较简单的基础功能模块,主要提供对epoll系统调封装的接口。

  • 功能:对任意描述符进行IO事件监控
  • 意义:封装epoll,简化描述符事件监控操作
  • 功能接口:
    1. 添加事件监控(针对Channel模块 )
    2. 修改事件监控
    3. 移除事件监控

Channel模块启用监控、移除监控等功能,都是通过调用该模块的封装完成的。

模块设计

  1. 需具备 epoll 的操作句柄。
  2. 拥有 struct epoll_event 结构数组,用于监控时保存所有活跃事件。
  3. 利用哈希表管理描述符及其对应的事件管理 Channel 对象。

逻辑流程

  1. 对描述符进行监控,通过 Channel 明确描述符需要监控的事件。
  2. 当描述符就绪时(描述符有事件就绪时),借助哈希表根据描述符找到对应的 Channel(通过 Channel 确定事件的处理方式),并返回就绪描述符对应的 Channel
c++ 复制代码
const int MAX_EPOLLEVENTS = 1024;
class Poller
{
private:
    int _epfd;                                      //epoll文件描述符
    struct epoll_event _evs[MAX_EPOLLEVENTS];       //存放就绪事件的数组
    std::unordered_map<int,Channel*> _channels;     //建立epfd到channel指针的映射

    //对epoll的直接操作
    void Update(Channel* channel,int op)
    {
        // int epoll_ctl(int epfd, int op,  int fd,  struct epoll_event *ev);
        int fd = channel->Fd();
        struct epoll_event ev;
        ev.data.fd = fd;
        ev.events = channel->Events();
        int ret = epoll_ctl(_epfd,op,fd,&ev);
        if(ret < 0)
        {
            ERR_LOG("EPOLLCTL FAILED!!");
        }
    }
    //判断一个Channel是否已经添加了事件监控
    bool HasChannel(Channel* channel)
    {
        auto it = _channels.find(channel->Fd());
        if(it == _channels.end())
        {
            return false;
        }
        return true;
    }
public:
    Poller()
    {
        _epfd = epoll_create(MAX_EPOLLEVENTS);
        if(_epfd < 0)
        {
            ERR_LOG("EPOLL CREATE FAILED!!");
            abort();//直接退出
        }
    }
    //添加或者修改监控事件
    void UpdateEvent(Channel* channel)
    {
        bool ret = HasChannel(channel);
        if(ret == false)
        {
            //不存在则添加
            _channels.insert(std::make_pair(channel->Fd(),channel));
            Update(channel,EPOLL_CTL_ADD);
        }
        //存在则修改
        Update(channel,EPOLL_CTL_MOD);
    }
    //移除监控
    void RemoveEvent(Channel* channel)
    {
        auto it = _channels.find(channel->Fd());
        if(it != _channels.end())
        {
            _channels.erase(it);
        }
        Update(channel,EPOLL_CTL_DEL);
    }
    //开始监控,返回活跃连接
    void Poll(std::vector<Channel*>* active)
    {
        // int epoll_wait(int epfd, struct epoll_event *evs, int maxevents, int timeout)
        int nfds = epoll_wait(_epfd,_evs,MAX_EPOLLEVENTS,-1);//阻塞模式
        if(nfds < 0)
        {
            if(errno == EINTR)
            {
                return;
            }
            ERR_LOG("EPOLL WAIT ERROR:%s",strerror(errno));
            abort();
        }

        for(int i = 0;i < nfds;i++)
        {
            auto it = _channels.find(_evs[i].data.fd);
            assert(it != _channels.end());
            it->second->SetEvents(_evs[i].events);//设置实际就绪事件
            active->push_back(it->second);
        }
    }
};
相关推荐
深圳市恒讯科技2 小时前
服务器与普通个人电脑的主要区别是什么?
运维·服务器
FMRbpm2 小时前
链表5--------删除
数据结构·c++·算法·链表·新手入门
Highcharts.js2 小时前
在Python中配置高度交互的数据可视化:Highcharts完全指南
开发语言·python·信息可视化·highcharts
小生凡一2 小时前
图解|Go语言实现 Agent|LLM+MCP+RAG
开发语言·后端·golang
思茂信息2 小时前
CST电动车EMC仿真(二)——电机控制器MCU的EMC仿真
开发语言·javascript·单片机·嵌入式硬件·cst·电磁仿真
未来之窗软件服务2 小时前
服务器运维(十一)SQLite3 php封装——东方仙盟炼气期
运维·服务器·sqlite·服务器运维·数据库驱动·东方仙盟
开始了码3 小时前
关于qt运行程序点击几下未响应的原因
开发语言·qt
Kimser3 小时前
QT C++ QWebEngine与Web JS之间通信
javascript·c++·qt
QT 小鲜肉3 小时前
【QT/C++】Qt样式设置之CSS知识(系统性概括)
linux·开发语言·css·c++·笔记·qt