epoll

epoll的相关系统调用

epoll只有epoll_create,epoll_ctl,epoll_wait 3个系统调用。

1. int epoll_create(int size);

 

#include <sys/epoll.h>

int epoll_create(int size);
int epoll_create1(int flags);

 

描述
epoll_create() 创建一个 epoll 实例,并要求内核分配一个可以保存 size 个描述符的空间。size 不是可以保存的最大的描述符个数,而只是给内核规划内部结构的一个暗示。(现在,size 被忽略;参看下面的“注意”。)
epoll_create() 返回一个引用创建 epoll 实例的文件描述符。这个文件描述符用于接下来的所有 epoll 的接口。当没有更多请求时,epoll_create() 返回的文件描述符应该由 close(2) 关闭。当所有引用一个 epoll 实例的文件描述符都关闭时,内核将销毁该实例并释放相关资源以重新利用。

如果 flags 是 0,正如废弃不用的 size 参数一样,epoll_create1() 与 epoll_create() 没有区别。下面的 flags 的值会获得不同的行为:

EPOLL_CLOEXEC
    在新打开的文件描述符里设置 close-on-exec (FD_CLOEXEC) 标记。参看在 open(2) 里关于 O_CLOEXEC 标记的描述来了解这为什么有用。

返回值
成功时,这些系统调用返回非负的文件描述符。错误时,返回 -1,并把 errno 设置为合适的值。
创建一个epoll的句柄。自从linux2.6.8之后,size参数是被忽略的。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

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

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

第一个参数是epoll_create()的返回值。

第二个参数表示动作,用三个宏来表示:

EPOLL_CTL_ADD:注册新的fdepfd中;

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

EPOLL_CTL_DEL:从epfd中删除一个fd

第三个参数是需要监听的fd

第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:

 

typedef union epoll_data {  
    void *ptr;  
    int fd;  
    __uint32_t u32;  
    __uint64_t u64;  
} epoll_data_t;  
 //感兴趣的事件和被触发的事件  
struct epoll_event {  
    __uint32_t events; /* Epoll events */  
    epoll_data_t data; /* User data variable */  
}; 

 

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);

收集在epoll监控的事件中已经发送的事件。参数events是分配好的epoll_event结构体数组,epoll将会把发生的事件赋值到events数组中(events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存)maxevents告之内核这个events有多大,这个 maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。如果函数调用成功,返回对应I/O上已准备好的文件描述符数目,如返回0表示已超时。

 

epoll工作原理

 

epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也mmap 

 

另一个本质的改进在于采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。

 

 

 

posted @ 2015-12-04 15:56  牧 天  阅读(360)  评论(0)    收藏  举报