C++仿muduo库高并发服务器项目:Poller模块
前言
本篇文章所讲的是本人的个人项目仿muduo库高并发服务器中的Poller模块实现部分。
Poller模块介绍:
这也是一个比较简单的基础功能模块,主要提供对epoll系统调封装的接口。
- 功能:对任意描述符进行IO事件监控
- 意义:封装epoll,简化描述符事件监控操作
- 功能接口:
- 添加事件监控(针对Channel模块 )
- 修改事件监控
- 移除事件监控
Channel模块启用监控、移除监控等功能,都是通过调用该模块的封装完成的。
模块设计
- 需具备
epoll的操作句柄。 - 拥有
struct epoll_event结构数组,用于监控时保存所有活跃事件。 - 利用哈希表管理描述符及其对应的事件管理
Channel对象。
逻辑流程
- 对描述符进行监控,通过
Channel明确描述符需要监控的事件。 - 当描述符就绪时(描述符有事件就绪时),借助哈希表根据描述符找到对应的
Channel(通过Channel确定事件的处理方式),并返回就绪描述符对应的Channel。
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);}}
};
