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);
        }
    }
};
相关推荐
小肝一下13 小时前
c++从入门到跑路——string类
开发语言·c++·职场和发展·string类
无巧不成书021813 小时前
Unicode编码机制全解析:从核心原理到Java 实战
java·开发语言·java字符编码·unicode 15.1码点
楼田莉子13 小时前
设计模式:构造器模式
开发语言·c++·后端·学习·设计模式
lly20240613 小时前
Swift 析构过程
开发语言
mu_guang_13 小时前
计算机体系结构3-cache一致性和内存一致性的区别
java·开发语言·计算机体系结构
邪修king13 小时前
UE5 零基础入门第二弹:让你的几何体 “活” 起来 ——Actor 基础与蓝图交互入门
c++·ue5·交互
cyber_两只龙宝13 小时前
【Oracle】Oracle之DQL中SELECT的基础使用
linux·运维·服务器·数据库·云原生·oracle
lingggggaaaa13 小时前
PHP模型开发篇&MVC层&动态调试未授权&脆弱鉴权&未引用&错误逻辑
开发语言·安全·web安全·网络安全·php·mvc·代码审计
星原望野13 小时前
java:volatile关键字的作用
java·开发语言·volatile
Deitymoon13 小时前
linux——TCP多进程并发服务器
linux·服务器·tcp/ip