epoll是实现IO多路转接的另一种方式。它与select,poll的作用相同,都是一次等待多个文件描述符。但是,它在接口的使用及原理上与前两者有很大的不同。它改进了select和poll的缺点,使IO操作效率更高。因此它被公认为LInux2.6下性能最好的IO多路转接就绪通知方法。
下面具体介绍epoll的相关概念。
epoll
与select,poll不同的是,epoll在使用上有三个相关的系统调用。
1. epoll_create
函数原型
#include <sys/epoll.h>
int epoll_create(int size);
该函数的功能是创建一个epoll模型,然后返回一个epoll句柄(相当于文件描述符)。
参数size的作用是告诉内核关心的文件描述符数目有多大。但是从Liunx2.6.8之后,size参数是被忽略的。所以,这里不进行讨论。
该函数在调用时,会创建一个struct eventpoll结构体。在该结构体中有两个成员比较重要:
除了创建上述结构体,还会创建一个回调机制。回调机制的作用是当内核中有数据来时(满足就绪条件时),通知操作系统,这样,操作系统就不用再遍历等待满足就绪条件的文件描述符。
总结一下,在该函数内部实现以下功能(这些结构如何使用,后续进行说明):
(1)建立回调映射机制
(2)创建一棵空的红黑树;
(3)创建一个空的就绪队列;
2. 注册函数epoll_ctl
函数原型
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
参数说明:
epfd:上述epoll模型的句柄
op:表示采取的操作,该变量的取值有如下几种:
EPOLL_CTL_ADD:将fd注册到epoll模型中
EPOLL_CTL_MOD:修改已经注册到epoll模型的的事件类型
EPOLL_CTL_DEL:删除已经注册到epoll模型中的fd。
fd:对哪个文件描述符进行上述操作
event:表示监听的文件描述符fd上的相关事件信息。该结构体定义如下:
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
第一个成员变量表示事件类型,该变量与poll中的events和revents的含义类似。取值都是一个宏,不同的宏表示不同的事件类型,常见的宏为:EPOLLIN(读事件),EPOLLOUT(写事件),EPOLLET(将EPOLL设置为边缘触发,具体使用后面再详细说明)。
第二个成员变量为一枚举类型变量,结构定义如下:
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
因为是枚举类型,所以每次在使用时都只能取其中的一个成员变量。fd表示关心的文件描述符,用于存放一个int类型的数据。后两个变量分别用于存放32和64位的数据,具体存放什么数据在实际使用的时候在具体讨论。ptr为一指针,可以接受任意类型的数据,如果关心的文件描述符上的事件除了需要存放fd外,还需要存放其他的变量,此时就可以使用该变量(具体使用后面说明)。
该函数用于注册监听文件描述符上的事件。
1. 如果是添加事件,该函数的功能是:对该文件描述符上的事件建立回调映射关系;将该文件描述符上的事件添加进epoll模型的红黑树中;如果该文件描述符上的事件就绪了,则将文件描述符上的事件添加进epoll模型中