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);
        }
    }
};
相关推荐
looking_for__2 小时前
【Linux】应用层自定义协议与序列化
linux·服务器·网络
仰泳的熊猫2 小时前
题目1453:蓝桥杯历届试题-翻硬币
数据结构·c++·算法·蓝桥杯
rainbow68892 小时前
C++STL list容器模拟实现详解
开发语言·c++·list
云中飞鸿2 小时前
VS编写QT程序,如何向linux中移植?
linux·开发语言·qt
唐梓航-求职中2 小时前
技术-算法-leetcode-1606. 找到处理最多请求的服务器(易懂版)
服务器·算法·leetcode
Boop_wu2 小时前
简单介绍 JSON
java·开发语言
超龄超能程序猿2 小时前
Python 反射入门实践
开发语言·python
Katecat996632 小时前
Faster R-CNN在药片边缘缺陷检测中的应用_1
开发语言·cnn
会叫的恐龙2 小时前
C++ 核心知识点汇总(第11日)(排序算法)
c++·算法·排序算法
晚风_END2 小时前
Linux|操作系统|elasticdump的二进制方式部署
运维·服务器·开发语言·数据库·jenkins·数据库开发·数据库架构