1 初识epoll
1.epoll是Linux内核为处理大批量文件描述符而作了改进的poll;
2.epoll是Linux下多路复用IO接口select/poll的增强版本;
3.epoll能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。
2 epoll相关的系统调用
1.epoll_create
(1)函数原型:
#include <sys/epoll.h>
int epoll_create(int size);
//在linux2.6.8之后,size参数是被忽略的
(2)作用:用来创建一个epoll句柄(或者说是epoll对象);
(3)返回值:调用epoll_create函数,成功之后会返回一个文件描述符,这个文件描述符也就是创建出来的epoll对象,所以当用完之后需要调用close函数来关闭这个文件描述符,否则会导致文件描述符用尽。
2.epoll_ctl
(1)函数原型:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
(2)作用:对epoll对象epfd,对于文件描述符fd执行什么样的操作,可以将fd注册进epfd中,也可以删除epfd中的fd,还可以修改fd监听的事件。
(3)函数参数:
epfd:是epoll_create函数创建的epoll对象
op:对该epfd的相关操作
fd:需要监听的文件描述符
event:是一个结构体的地址,该结构体用来告诉内核需要监听的事件是什么,需要监听的数据是什么类型的
(4)epoll_event结构体
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
}__EPOLL_PACKED;
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t; //保存触发事件的某个文件描述符相关的数据
(5)epoll_ctl第二个参数op的取值:
EPOLL_CTL_ADD:注册新的文件描述符到epoll对象epfd中
EPOLL_CTL_DEL:在epfd中,根据文件文件描述符fd删除指定的fd对应的相关信息
EPOLL_CTL_MOD:修改已经注册的fd的监听事件
3.epoll_wait
(1)函数原型:
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
(2)作用:收集在epfd中已经就绪的事件
(3)参数:
events:这里的events是一个struct epoll_event的数组,该数组里面存放内核拷贝至用户空间中已经就绪的文件描述符相关信息,该数组的每个元素都是一个epoll_event的结构体
maxevents:表示events数组的大小
timeout:表示超时时间,以毫秒为单位,如果为0则不会阻塞立即返回,-1是永久阻塞
(4)返回值:
大于0:返回IO中已经准备好的文件描述符的个数
-1:表示函数调用出错
等于0:表示超时
3 epoll的工作原理
3.1 每一个epoll对象都有一个独立的eventpoll结构体
该结构体内容如下:
//eventpoll结构体
struct eventpoll {
spinlock_t lock; /* Protect the access to this structure */
struct mutex mtx;
wait_queue_head_t wq; /* Wait queue used by sys_epoll_wait(),epoll文件的等待队列(是一个双链表)*/
/*调用epoll_wait的进程可能在此队列上睡眠, 等待ep_poll_callback()函数唤醒或超时 */
wait_queue_head_t poll_wait;
struct list_head rdllist; /* List of ready file descriptors (就绪链表,双向链表,用于存放将要通过epoll_wait返回给用户的满足条件的文件描述符的相关结构)*/
struct rb_root rbr; /* RB tree root used to store monitored fd structs (红黑树的根节点用于存储所有添加到epoll中的需要监控的事件)*/
struct epitem *ovflist; /* This is a single linked l