epoll理解及应用
基于select的I/O复用技术速度慢的原因
--调用select函数后常见的针对所有文件描述符的循环语句。
--每次调用select函数时都需要向该函数传递监视对象信息。(即每次调用select函数时向操作系统传递监视对象信息)
select的优点
如果需要满足如下两个条件,则可以选用select模型:
--服务器端接入者少
--程序应具有兼容性
epoll只在Linux下提供支持。
实现epoll时必要的函数和结构体
epoll的优点:
--无需编写以监视状态变化为目的的针对所有文件描述符的循环语句。
--调用对应于select函数的epoll_wait函数时无需每次传递监视对象信息。
epoll服务器端实现需要的3个函数:
--epoll_create: 创建保存epoll文件描述符的空间
--epoll_ctl: 向空间注册并注销文件描述符
--epoll_wait: 与select函数类似,等待文件描述符发生变化
select方式中用fd_set变量负责保存监视对象文件描述符,而epoll方式由操作系统保存,因此需要向操作系统请求创建保存文件描述符的空间,使用epoll_create函数。
select方式通过fd_set变量监视对象的状态变化,而epoll方式中通过如下结构体epoll_event将发生变化的文件描述符单独集中到一起:
struct epoll_event
{
__unit32_t events;
epoll_data_t data;
}
typedef union epoll_data
{
void *ptr;
int fd;
__unit32_t u32;
_-unit64_t u64;
}epoll_data_t;
声明足够大的epoll_event结构体数组后,传递给epoll_wait函数时,发生变化的文件描述符信息将被填入该数组。
epoll_create函数
调用epoll_create函数时创建的文件描述符保存空间称为"epoll例程"。size本该决定epoll例程的大小,但Linux 2.6.8之后的内核将完全忽略size参数,内核会根据情况调整epoll例程的大小。
epoll_create返回的文件描述符主要用于区分epoll例程。
epoll_ctl函数
生成epoll例程后,应在其内部注册监视对象文件描述符,此时使用epoll_ctl函数。
例:
1
epoll_ctl(A,EPOLL_CTL_ADD,B,C);
此语句的含义:epoll例程A中注册文件描述符B(EPOLL_CTL_ADD),主要目的是监视参数C中的事件。
1
epoll_ctl(A,EPOLL_CTL_DEL,B,NULL);
含义: 从epoll例程A中删除文件描述符B
第二个参数传递的常量及含义:
第四个参数epoll_event结构体指针:
epoll_event结构体用于保存发生事件的文件描述符集合。但也可以在epoll例程中注册文件描述符时,用于注册关注的事件。
struct epoll_event event;
...
event.events = EPOLLIN; //发生需要读取数据的情况
event.data = sockfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);
...
上述代码将sockfd注册到epoll例程epfd中,并在需要读取数据的情况下产生相应事件。
epoll_event的成员events中可以保存的常量及所指的事件类型:
epoll_wait函数
该函数调用方式如下:第二个参数所指缓冲需要动态分配
int event_cnt;
struct epoll_event * ep_events;
.....
ep_e