同其他I/O多路复用和信号驱动一样,linux的epoll(event poll)API可以检查多个文件描述符上的I/O就绪状态。Epoll API的主要优点如下。
当检查大量的文件描述符时,epoll的性能延展性比select和poll高很多。
epoll API既支持水平触发也支持边缘触发。与之相反,select和poll只支持水平触发,而信号驱动I/O只支持边缘触发。
epoll API的核心数据结构称为epoll实例, 它和一个打开的文件描述符相关联。这个文件描述符不是用来做I/O操作的,相反,他说内核数据结构的句柄,这些内核数据结构实现了两个目的。
记录了在进程中声明过的感兴趣的文件描述符列表--interest list。
维护了处于I/O就绪态的文件描述符列表--ready list。
ready list中的成员是interest list的子集。
epoll API由以下3个系统调用组成。
系统调用epoll_create()创建一个epoll实例,返回代表该实例的文件描述符。
系统调用epoll_ctl()操作同epoll实例相关的兴趣列表。通过epoll_ctl(),我们可以增加新的描述符到列表中,将已有的文件描述符从该列表中移除,以及修改代表文件描述符上事件类型的位掩码。
系统调用epoll_wait()返回与epoll实例相关联的就绪列表中的成员。
创建epoll实例:epoll_create():
系统调用epoll_create()创建了一个新的epoll实例,其对应的兴趣列表初始化为空。
修改epoll的兴趣列表:epoll_ctl():
系统调用epoll_ctl()能够修改由文件描述符epfd所代表的epoll实例中的兴趣列表。
参数fd指明了要修改兴趣列表中的哪-一个文件描述符的设定。该参数可以是代表管道、套接字、 POSIX 消息队列等。但是,这里fd不能作为普通文件或目录的文件描述符(会出现EPERM 错误)参数op用来指定需要执行的操作,它可以是如下几种值。
事件等待:epoll_wait():
系统调用epoll_wait()返回epoll实例中处于就绪态的文件描述符信息。单个epoll_wait()调用能返回多个就绪态文件描述的信息。
参数events所指向的结构体数组中返回的是有关就绪态文件描述符的信息。数组events的空间由调用者负责申请,所包含的元素个数在参数maxevents中指定。当我们调用epoll_ctl将文件描述符添加到兴趣列表中时,应该要么将event.data.fd设为文件描述符号,要么将event.data.ptr设为指向包含文件描述符号的结构体。调用成功后,epoll_wait()返回数组events中的元素个数。
epoll中events字段上的位掩码值:
EPOLLONESHOT标志:
如果指定了这个标志,那么在下一个epoll_wait()调用通知我们对应的文件描述符处于就绪态后,这个描述符就回在兴趣列表中被标记为非激活态,之后的epoll_wait调用都不会再通知我们有关这个描述符的状态了。
上代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERPORT 8000
#define SERIP "192.168.6.174"
int main(int argc, char* argv[])
{
int lfd = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in seraddr,cliaddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(SERPORT);
int dst;
inet_pton(AF_INET,SERIP,(void*)&dst);
seraddr.sin_addr.s_addr = dst ;
int ret = bind(lfd,(struct sockaddr*)&seraddr,sizeof(seraddr));
listen(lfd,64);
socklen_t addrlen = sizeof(cliaddr);
char buf[1024];
char clip[32];
int i;
//将lfd交给epoll监听
int epfd = epoll_create(64);
struct epoll_event events[1025], event;
event.events = EPOLLIN;
event.data.fd = lfd;
epoll_ctl(epfd, EPOLL_CTL_ADD,lfd, &event);
while(1){
int eret = epoll_wait(epfd, events, 1025, -1);
if(eret<0){
perror("epoll_wait error");
exit(1);
}
for(i = 0;i