C++实战——Epoll功能的封装

文章代码来源:高并发Web服务器

简单介绍(后面去其他博客搜刮一下补充一波)

非阻塞同步IO所要用到的一个功能。这个项目中对这部分功能进行了很好的封装。简单介绍一下Epoll的作用。当服务器的负责监听的文件描述符发生改动,表示有连接进来。Epoll会将新的文件描述符与其对应事件加入,后面调用自身的一些方法,去监听这些连接文件描述符,有数据变动说明有数据进来,就返回这些有数据的文件描述符的列表。那么主线程通过列表中的这些文件描述符就可以拿到数据,然后分发给各个线程。

API及其具体实现如下:

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
//epoll.h
#ifndef EPOLLER_H
#define EPOLLER_H

#include <sys/epoll.h> //epoll_ctl()
#include <fcntl.h> // fcntl()
#include <unistd.h> // close()
#include <assert.h> // close()
#include <vector>
#include <errno.h>

class Epoller {
public:
explicit Epoller(int maxEvent = 1024); //最大检测到的Epoll数量

~Epoller();
bool AddFd(int fd, uint32_t events); //添加要检测的事件

bool ModFd(int fd, uint32_t events); //修改

bool DelFd(int fd); //删除

int Wait(int timeoutMs = -1); //让内核去检测

int GetEventFd(size_t i) const; //获取

uint32_t GetEvents(size_t i) const;

private:
int epollFd_; //通过这个东西可以操作某个Epoller对象

std::vector<struct epoll_event> events_; //检测到的事件集合
};

#endif //EPOLLER_H
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
//epoll.cpp


#include "epoller.h"

//创建和释放
Epoller::Epoller(int maxEvent):epollFd_(epoll_create(512)), events_(maxEvent){
assert(epollFd_ >= 0 && events_.size() > 0);
}

Epoller::~Epoller() {
close(epollFd_);
}

//文件描述符与事件
bool Epoller::AddFd(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_ADD, fd, &ev);
}
//修改
bool Epoller::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 Epoller::DelFd(int fd) {
if(fd < 0) return false;
epoll_event ev = {0};
return 0 == epoll_ctl(epollFd_, EPOLL_CTL_DEL, fd, &ev);
}
//
int Epoller::Wait(int timeoutMs) {
return epoll_wait(epollFd_, &events_[0], static_cast<int>(events_.size()), timeoutMs);
}
//获取所有的 有数据的 文件描述符 但是是根据索引获取指定的fd
int Epoller::GetEventFd(size_t i) const {
assert(i < events_.size() && i >= 0);
return events_[i].data.fd;
}
//只是简单获取Events;
uint32_t Epoller::GetEvents(size_t i) const {
assert(i < events_.size() && i >= 0);
return events_[i].events;
}