概述
epoll是Linux特有的I/O复用函数。它在现实和使用上与select,poll由很大的差异。首先,epoll使用一组函数来完成任务,而不是单个函数。其次,epoll把用户关心的文件描述符上的事件放在内核里的一个事件表中,从而无须像select和poll那样每次调用都要重复传入文件描述符集或事件集。但epoll需要使用一个额外的文件描述符,来唯一标识内核中的这个事件表,这个文件描述符使用使用如下epoll_create函数来创建:
#inlcude<sys/epoll.h>
int epoll_create(int size)
size参数提示内核事件表需要多大。该函数返回的文件描述符将用作其他所有epoll系统调用的第一个参数,以指定要访问的内核事件表。
#include<sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
fd参数是要操作的文件描述符,op参数则指定操作类型。操作类型有:
EPOLL_CTL_ADD, 往事件表中注册fd上的事件。
EPOLL_CTL_MOD, 修改fd上的注册事件。
EPOLL_CTL_DEL, 删除fd上的注册事件。
event参数指定事件,他是epoll_event结构指针类型。epoll_event的定义如下:
struct epoll_event
{
__unit32_t events; //epoll事件
epoll_data_t data; //用户数据
};
#include<sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);
timeout参数与poll函数的timeout参数相同。
maxevents参数指定最多监听多少个事件,它必须大于0.
epoll_wait函数如果检测到事件,就将所有就绪的事件从内核事件表(由epfd参数指定)中复制到他的第二个参数events指向的数组中。这个数组值输出epoll_wait检测到的就绪事件。
epoll对文件描述符由两种模式为LT模式和ET模式。LT模式是默认的工作模式,在此模式下epoll相当与高效的poll。而当往内核事件表中注册一个文件描述符上的EPOLLET事件时,epoll将以ET模式来操作该文件描述符。
eg:
#define MAX_EVENT_NUMBER 1024
#define BUFFER_SIZE 10
int setnonblocking(int fd)
{
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return old_option;
}
void addfd(int epollfd, int fd, int enable_et)
{
struct epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN;
if (enable_et)
{
event.events |= EPOLLET;
}
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
setnonblocking(fd);
}
void lt(struct epoll_event *events, int number, int epollfd, int listenfd)
{
char buf[BUFFER_SIZE];
for (int i = 0; i < number; i++)
{
int sockfd = events[i].data.fd;
if (listenfd == sockfd)
{
struct sockaddr_in client_address;
socklen_t client_addrlength = sizeof(client_address);
int connfd = accept(listenfd, (struct sockaddr *) &client_address, &client_addrlength);
addfd(epollfd, connfd, 0);
}
else if (events[i].events & EPOLLIN)
{
printf("event trigger oncen");
memset(buf, '