linux中epoll模型

时间:2023-01-07 03:33:13

epoll是linux内核为处理大批量文件描述符而作了改进的poll,是linux下IO复用select/poll的增强版本。

一、epoll的主要接口是:

1、创建

(1)int epoll_create(int maxfds);

maxfds是支持的最大句柄数。该函数会返回一个新的epoll句柄,之后的函数调用都用这个句柄来操作。用完之后,记得用close()关闭这个创建出来的epoll句柄,否则可能导致系统fd被耗尽。

(2)int epoll_reate1(int flag);

上面创建的方法在linux 2.6.8之后,maxfds是被忽略的,所以建议采用epoll_create1(0)这种方法。另外epoll_create1(EPOLLCLOEXEC)表示生成的epoll fd具有“执行后关闭”的特性。

2、事件注册

int epoll_ctl(int epfd,int op,int fd,struct epoll_event* event);

epoll的事件注册函数,它不同于select/poll在监听的时候告诉内核要监听什么事件,而是先注册要监听的事件类型。

(1)epfd为(1)返回的epoll句柄

(2)op表示动作,用三个宏来表示:

EPOLL_CTL_ADD:注册新的fd到epfd中

EPOLL_CTL_MOD:修改已注册的fd的监听事件

EPOLL_CTL_DEL:从epfd中删除一个fd

(3)fd为要监听的fd

(4)event为要监听的事件,结构如下:

struct epoll_event

{

__uint32_t events;

epoll_data_t data;

};

events可以是一下宏的集合:

EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);

EPOLLOUT:表示对应的文件描述符可以写;

EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);

EPOLLERR:表示对应的文件描述符发生错误;

EPOLLHUP:表示对应的文件描述符被挂断;

EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。

EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

3、等待事件发生

int epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout);

等待事件发生,类似于select()调用。参数events用来从内核得到事件的集合,maxevents告诉内核这个events有多大,maxevents不能大于epoll_create时设置的size,参数timeout是超时时间(毫秒,0立即返回,-1将永久阻塞)。该函数返回需要处理的事件数目,如果返回0表示已超时。

二、epoll的两种工作模式

epoll默认的工作模式是Level Triggered,通过epoll_ctl可以设置epoll的工作模式为Edge Triggered。

LT(levet triggered)同时支持block和no-block socket。在该模式下,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错的可能性要小一点。传统的select/poll都是这种模型的代表。

ET(edge triggered)是高速工作方式,只支持non-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。如果描述符没有再次发生IO操作(导致它再次变成未就绪),内核不会发送更多的通知。例如:ET模式下epoll_wait返回,当前缓存中接收到了2KB的数据,调用read读取1KB的数据。下次循环调用epoll_wai时将不会受到内核通知,将阻塞在这里,直到发生IO操作(如又收到数据)。当调用read或者write返回EAGAIN时,才需要挂起。但我们一般在处理循环读时,当read()返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。

三、epoll相对于select/poll的优势

1、epoll通过epoll_ctl注册监听的事件,而不像select/poll在每次循环调用select/poll函数时,设置监听事件,把fd集合从用户态拷贝到内核态),这个开销在fd很多时会很大。

2、select/poll在监听事件发生后,需要遍历所有fd,这个开销在fd很多时也很大,而epoll_wait返回的就是需要处理的事件。

3、select支持的最大文件描述符个数默认为1024,不适合处理大批量的文件描述符。而epoll就没有限制。

4、在并发连接数较大而活动连接数较小时,epoll比poll效率更高;而如果所有连接基本都是活跃的,比如一个高速LAN环境,epoll并不比select/poll有什么效率。