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);
        }
    }
};
相关推荐
OpenCloudOS5 小时前
从快速响应到问题发现:一次backport挖出全新漏洞CVE-2026-76641
服务器·网络·安全
DevHub6 小时前
QEMU + Busybox 搭建嵌入式 Linux 开发环境:内核编译到启动,30 秒一个迭代
linux·运维·服务器
2401_890603406 小时前
Linux 基础文件IO
linux·运维·服务器
m0_547486666 小时前
《JavaScript核心原理 》全套PPT课件2026
开发语言·javascript·ecmascript
老当益壮梁奶奶6 小时前
Linux软件编程学习笔记(七):线程分离与线程间通信详解
linux·c语言·c++·笔记·学习
Awh-6 小时前
Linux软件应用编程 第一章中:Linux文件操作
linux·运维·服务器
MC皮蛋侠客7 小时前
Tauri 2.x 系列(五):调用系统 API——官方插件、Rust crate 与原生能力
开发语言·后端·rust
布莱克6057 小时前
软中断和硬中断的区别
开发语言·操作系统
whcyhhh8 小时前
头歌实践教学平台:数据科学与大数据技术导论(十二)
大数据·开发语言·python·数据清洗
Tim风声(网络工程师)8 小时前
Kail下载
linux·运维·服务器