仿muduo库实现高并发服务器-----Channel模块 和 Poller模块

一、Channel模块用于事件管理

成员变量:

描述符

使用uint32_t 类型来表示需要监控的事件

使用uint32_t类型来表示当前链接触发的事件

可读事件被触发的回调函数

可写事件被触发的回调函数

错误事件被触发的回调函数

链接断来事件被触发的回调函数

任意事件被触发的回调函数

成员函数

返回文件描述符

返回想要监控的事件

设置当前链接出发的事件

设置可读事件 可读事件被触发的回调函数 可写事件被触发的回调函数 错误事件被触发的回调函数 链接断来事件被触发的回调函数 任意事件被触发的回调函数

是否监控了可读 是否监控了可写

启动读事件和写事件 关闭写事件和读事件监控

移除和更新具体需要其他模块支持

监控触发事件

全部代码

cpp 复制代码
class Channel
{
private:
    uint32_t _events;
    uint32_t _revents;
    int _fd;
    EventLoop *_loop;
    using EventCallBack = std::function<void()>;
    EventCallBack _read_callback;
    EventCallBack _write_callback;
    EventCallBack _error_callback;
    EventCallBack _close_callback;
    EventCallBack _event_callback;

public:
    Channel(EventLoop *loop, int fd) : _fd(fd), _loop(loop), _events(0), _revents(0)
    {
    }
    uint32_t Event()
    {
        return _events;
    }
    int Fd()
    {
        return _fd;
    }
    void SetEvent(uint32_t events)
    {
        _revents = events;
    }
    void SetReadCallback(const EventCallBack &cd)
    {
        _read_callback = cd;
    }
    void SetWriteCallback(const EventCallBack &cd)
    {
        _write_callback = cd;
    }
    void SetErrorCallback(const EventCallBack &cd)
    {
        _error_callback = cd;
    }
    void SetCloseCallback(const EventCallBack &cd)
    {
        _close_callback = cd;
    }
    void SetEventCallback(const EventCallBack &cd)
    {
        _event_callback = cd;
    }
    bool ReadAble() // 是否监控了可读
    {
        return _events & EPOLLIN;
    }
    bool WriteAble()
    {
        return _events & EPOLLOUT;
    }
    void EnableRead() // 启动读事件监控
    {
        _events |= EPOLLIN;
        Update();
    }
    void EnableWrite()
    {
        _events |= EPOLLOUT;
        Update();
    }
    void DisableRead()
    {
        _events &= ~EPOLLIN;
        Update();
    }
    void DisableWrite()
    {
        _events &= ~EPOLLOUT;
        Update();
    }
    void DisableAll()
    {
        _events = 0;
        Update();
    }
    void Remove();
    void Update();
    // 事件处理 一旦链接接触了事件,就调用了这个函数,自己触发什么自己决定
    void HandleEvents()
    {
        if (_revents & EPOLLIN || _revents & EPOLLRDBAND || _revents & EPOLLPRI)
        {
           
            if (_read_callback)
                _read_callback();
        }
        if (_revents & EPOLLOUT)
        {
            if (_event_callback)
                _event_callback();
            if (_write_callback)
                _write_callback();
        }
        else if (_revents & EPOLLERR)
        {
            if (_error_callback)
                _error_callback();
        }
        else if (_revents & EPOLLHUP)
        {
            if (_close_callback)
                _close_callback();
        }
         if (_event_callback)
                _event_callback();
    }
};

Poller

采用epoll进行监听

成员变量:

文件描述符

监听就绪数组

建立文件描述符和Channel的关系变找到该文件描述符是否存在添加了事件监控

成员函数:

创造一个epoll

更新监控

判断一个Channel是否已经添加了事件监控

移除监控

开始监控并返回活跃链接

全部代码

cpp 复制代码
#define MAX_EPOLLEVENTS 1024
class Poller
{
private:
    int _epfd;
    std::unordered_map<int, Channel *> _channels;
    struct epoll_event _evs[MAX_EPOLLEVENTS];
    void Update(Channel *channel, int op)
    {
        int fd = channel->Fd();
        struct epoll_event ev;
         memset(&ev, 0, sizeof(ev)); 
        ev.data.fd = fd;
        ev.events = channel->Event(); 
        int ret = epoll_ctl(_epfd, op, fd, &ev);
       
        if (ret < 0)
        {
             ERR_LOG("EPOLLCTL FAILED! errno: %d, %s", errno, strerror(errno));
            abort();
        }
        return;
    }

public:
    Poller()
    {
        _epfd = epoll_create(MAX_EPOLLEVENTS);
        if (_epfd < 0)
        {
            ERR_LOG("EPOLL_CREATE FAILED");
            abort();
        }
    }
    bool HasChannel(Channel *channel)
    {
        auto it = _channels.find(channel->Fd());
        if (it == _channels.end())
        {
            return false;
        }
        return true;
    }
    // 修改添加事件监控
    void UpdateEvent(Channel *channel)
    {
        if (HasChannel(channel) == false)
        {
            Update(channel, EPOLL_CTL_ADD);
            _channels.insert(std::make_pair(channel->Fd(), channel));
            return;
        }
        return 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 nfds = epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, -1);
        if (nfds < 0)
        {
            if (errno == EINTR)
            {
                return;
            }
            ERR_LOG("EPOLL_WAIT FAILED");
            abort();
        }
        for (int i = 0; i < nfds; i++)
        {
            auto it = _channels.find(_evs[i].data.fd);
            assert(it != _channels.end());
            it->second->SetEvent(_evs[i].events);
            active->push_back(it->second);
        }
    }
};
相关推荐
kaixin_learn_qt_ing8 小时前
Electron程序---初体验
javascript·electron
星夜夏空998 小时前
网络编程(5)—— Reactor实现(v1)
服务器·javascript·网络
YWL8 小时前
OpenLayers测距测面:完整测量工具
前端·javascript·vue.js·信息可视化·openlayers
电子云与长程纠缠8 小时前
UE5 Lyra PocketWorld进行3D内容UI预览 - 下
开发语言·学习·游戏·ui·ue5
zhanghaha13148 小时前
HTML系列教程:2_HTML 编辑器(零基础超详细讲解
前端·编辑器·html
半旧5188 小时前
【Java Web02】WEB服务器内部实现技术揭秘
java·服务器·前端
平常心的技术小牛8 小时前
Qt-快速上手-QLabel
开发语言·qt
XR1234567888 小时前
工厂办公楼无线网络:多楼层覆盖与访客体验怎么选?
开发语言·php
拿本唠嗑AI研究8 小时前
现代前端架构爬虫指南:从静态页面到 React/Vue 单页应用
前端·爬虫·架构
JL158 小时前
Java并发编程面试全攻略-从synchronized到AQS底层原理
java·开发语言·面试·并发编程