前言
接着上一篇博客WebServer模块单元测试 | JySama,写得太多了代码解析就很慢了,重新开一篇。
epoll封装
上一篇末尾给出了epoll的实例,每次添加事件、修改事件、删除事件都是差不多的流程,可以封装一下,并且epollfd的create和close可以变成RAII的管理模式。
因为上层调用时,事件的类型是不一样的(读转读、读转写、写转写等),为了接口易用与通用,让上层传入events描述事件类型。events是一个uinit32_t,也即32位无符号整数类型。
封装很简单,只需要支持添加、修改、删除、调用epoll_wait、设置非阻塞(这个也让上层决定,默认非阻塞)即可。
设置非阻塞
这个功能设置在这里是因为每个要添加进来的事件都可以顺便进行阻塞与非阻塞的设置(而且一般来说事件的模式都是一致的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
int setFdNonblock(int fd) { return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); }
|
事件处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| bool addFd(int fd, uint32_t events) { if(fd < 0) return false; if(nonBlock && (setFdNonblock(fd)==-1)) return false;
epoll_event ev = {0}; ev.data.fd = fd; ev.events = events; return 0 == epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &ev); }
bool modFd(int fd, uint32_t events) { if(fd < 0) return false; epoll_event ev = {0}; ev.data.fd = fd; ev.events = events; return 0 == epoll_ctl(epollFd, EPOLL_CTL_MOD, fd, &ev); }
bool delFd(int fd) { if(fd < 0) return false; return 0 == epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, 0); }
|
返回就绪事件
这里上层创建一个events数组把地址传进来接收就绪事件,函数返回值是就绪事件个数。虽然c++定义一个结构体类型可以不写struct(c要),但还是写出来好些
1 2 3 4 5 6 7 8
|
int wait(vector<struct epoll_event> &evlist, int eventSize, int timeoutMs = 0) { struct epoll_event* evs = ; int res = epoll_wait(epollFd, events, eventSize, timeoutMs); for(int i=0,i<res;i++) evlist.push_back(events[i]); }
|
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| #ifndef EPOLLER_H #define EPOLLER_H
#include <sys/epoll.h> #include <fcntl.h> #include <unistd.h> #include <cassert> #include <vector> class Epoller { private: int eventSize; const bool nonBlock; int epollFd; std::vector<struct epoll_event> events; public: Epoller(const int eventsize = 1024, const bool ifNonBlock = true): eventSize(eventsize),nonBlock(ifNonBlock),epollFd(epoll_create(5)),events(eventsize) { assert(epollFd>=0); } ~Epoller() { close(epollFd); } int setFdNonblock(int fd) { return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); } bool addFd(int fd, uint32_t events) { if(fd < 0) return false; if(nonBlock && (setFdNonblock(fd)==-1)) return false;
epoll_event ev = {0}; ev.data.fd = fd; ev.events = events; return 0 == epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &ev); }
bool modFd(int fd, uint32_t events) { if(fd < 0) return false; epoll_event ev = {0}; ev.data.fd = fd; ev.events = events; return 0 == epoll_ctl(epollFd, EPOLL_CTL_MOD, fd, &ev); }
bool delFd(int fd) { if(fd < 0) return false; return 0 == epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, 0); } int wait(int timeoutMs = 0) { return epoll_wait(epollFd, &events[0], eventSize, timeoutMs); } int getEventFd(size_t i) { return events[i].data.fd; } uint32_t getEvents(size_t i) { return events[i].events; } };
#endif
|