epoll 是poll系统调用的升级版。可以用做单边沿(level-triggered)和双边沿(edge-triggered)的两种工作模式,同样也可以用于检测多个文件描述符。
用于创建一个epoll的实例对象。参数size代表可以一次性检测的文件对象的个数。返回值是epoll 实例对象的文件描述符,次描述符用于后续的epoll_ctl和epoll_wait函数中,当没有对象检测的时候,需要使用close系统调用关系该文件描述符,因为epoll实际上也会占用用一个fd的。
用于注册要检测的对象以及检测的事件。 epfd代表的是epoll的实例对象,也就是epoll_create的返回值。op代表的几种操作,如下:
EPOLL_CTL_ADD: 注册一个new的fd对象到epoll实例中。
EPOLL_CTL_MOD: 修改已经注册的fd的事件。
EPOLL_CTL_DEL: 从epoll检测的列表中remove掉fd。
event就是代表具体要检测的事件类型,详细信息如下:
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队列里
该系统调用用于等待检测对象的事件发生。 events具体返回具体的发生的事件内容,maxevents用于告知允许最大的事件数量,timout当然也就是超时时间,-1代表一直等待不超时。返回值代表发生事件需要处理的数据,返回值为0代表timeout。
#include <sys/epoll.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define EPOLL_INSTANCE_SIZE (8)
#define EPOLL_EVENTS_SIZE (8)
int main(int argc, char** argv)
{
int epfd;
int i = 0;
int events;
struct epoll_event eventItem[EPOLL_EVENTS_SIZE];
char buf[512];
/*usage*/
if(argc < 2 )
{
printf("Usage: %s <file1> <file2> ...\n", argv[0]);
return -1;
}
/*创建epoll实例对象*/
epfd = epoll_create(EPOLL_INSTANCE_SIZE);
if(epfd == -1)
{
printf("epoll_create error!\n");
return -1;
}
/*添加检测实例对象*/
for(i = 1; i < argc; i++)
{
int fd;
struct epoll_event event;
fd = open(argv[i], O_RDWR);
event.events = EPOLLIN;
event.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
}
while(1)
{
/*等待事件发生*/
events = epoll_wait(epfd, eventItem, EPOLL_EVENTS_SIZE, -1);
for(i = 0; i < events; i++)
{
int len = read(eventItem[i].data.fd, buf, 512);
buf[len] = '\0';
printf("read buf is %s\n",buf);
}
}
return 0;
}
测试结果:
1. 编译代码
gcc epoll.c -o epoll
2. 在tmp创建下创建3个fifo文件
mkfifo tmp/1 tmp/2 tmp3
3. 使用epoll在后台检测
./epoll tmp/1 tmp/2 tmp/3 &
可以从/proc/epoll进程的pid/fd中看到详细信息
4. echo 数据到 tmp/1中查看结果
test$ echo 111 > tmp/1
read buf is 111