@LIUHUAN
2016-05-06T21:03:17.000000Z
字数 3476
阅读 1205
Linux
c/c++
int epoll_create(int size);
int epoll_create1(int flags);
- 第一个函数epoll_create调用是比较常用的调用,第二个调用是改进版本。内核版本在2.9以及之后才能够使用。
- 调用成功的返回值,是一个文件描述符(非负整数),指向一个epoll实例,这个文件描述符代表这后续对于epoll相关接口的引用。需要在使用结束后调用close关闭文件描述符。
- 调用出现错误的返回值是-1,并可以在全局变量error中查看错误信息。
- 第一个调用的参数size是,调用者在后续使用epoll添加感兴趣的文件描述符个数的大小,这个是一个给系统初次分配epoll监控文件描述符数据结构的内存空间的一个参考值,但是如果后来调用者,监听的事件超过这个范围,那么系统会额外的分配空间的。
总的来说这个值只是操作系统的参考值。- epoll_create1参数是一个文件描述符标志,如果为0那么和 epoll_create(0)一样。
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *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 */
};
- epoll_event中events变量为事件发生的类型,可以是下面提到的事件类型EPOLLIN,EPOLLOUT,EPOLLHDUP,EPOLLPRI,EPOLLERR,EPOLLHUP,EPOLLET,EPOLLONESHOT,EPOLLWAKEUP中的一种,具体的参见下面的事件类型说明。
- data为一个联合体,可以根据不同的事件,来表示用户数据内容。例如可以是一个文件描述符。
fd为需要监控的文件描述符。在这里是根据这个文件描述符对后面的event结构进行操作的。具体见下面的op参数.
- EPOLL_CTL_ADD:将文件描述符fd关联到event结构当中,并把event事件添加到epfd实例当中。相当于把fd注册到epoll实例当中。
- EPOLL_CTL_MOD:根据文件描述符fd,来找到fd在epoll实例当中对应的event结构,修改这个event结构。
- EPOLL_CTL_DEL:根据文件描述符fd,找到其所对应的文件event结构,删除这个fd上面的事件监控。
- 总结下,epoll实际是通过fd来构建一个event事件,通过这个event结构来监控fd上面发生的文件事件操作。
epfd为epoll_create 或者epoll_create1函数调用的返回值,实际为一个文件描述符,指向epoll实例。epoll系统操作都是通过这个文件描述符来进行的。
- 调用成功返回0
- 失败返回-1,并置error错误信息。
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,
int maxevents, int timeout,const sigset_t *sigmask);
- timeout参数指定了在没有事件发生的时候epoll_wait调用阻塞的毫秒数(milliseconds)。
- 如果把这个值设置为-1,那么在没有事件发生时,这个调用会永远的阻塞下去。
- 如果timeout=0那么epoll_wait会检查监控的事件是否发生,然后立刻返回。
- 上面指的事件,可以包含监控的文件事件,也可以是信号中断事件。
- maxevent,是一次调用epoll_wait可以返回有监控事件发生的最大个数。
- 例如监控的事件中在某一时刻可能有20个发生了,但是如果这个时候maxevent=10,那么只会返回10个发生的事件。
- events表示的是一个struct epoll_event数组,存放的是某个时刻发生事件的结构体
- 可以在epoll_wait调用结束之后,来访问这个结构体里面的内容例如fd来处理发生的文件事件。
- epfd为epoll_create函数返回的文件描述符。epoll实例。
- 没有任何事件发生,或者超时返回0。
- 出现错误返回-1,并设置error错误信息。
- 返回监控事件发生的个数。
下面是一个处理多个客户端连接的服务端程序,可以根据这个大体的框架和自己的情况进行修改。
#include<stdio.h>
#include<unistd.h>
#include<sys/epoll.h>
#define MAX_EVENTS 10
int main (int argc,char* argv[] ) {
struct epoll_event ev, events[MAX_EVENTS];
int listen_sock, conn_sock, nfds, epollfd;
/* Code to set up listening socket, 'listen_sock',
(socket(), bind(), listen()) omitted */
/*创建epoll实例*/
epollfd = epoll_create1(0);
if (epollfd == -1) {
perror("epoll_create1");
exit(EXIT_FAILURE);
}
/*设置epoll_event,关联到epoll实例*/
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
/*注册listen_sock到epoll实例*/
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
perror("epoll_ctl: listen_sock");
exit(EXIT_FAILURE);
}
for (;;) {
/*监控事件的发生,-1表示检查监控的事件后立即返回*/
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
exit(EXIT_FAILURE);
}
/*遍历返回的事件,对事件进行处理*/
for (n = 0; n < nfds; ++n) {
/*如果是发生在接收连接的套接字上,那么接受客户端连接,并监控新建的连接文件事件*/
if (events[n].data.fd == listen_sock) {
conn_sock = accept(listen_sock,
(struct sockaddr *) &local, &addrlen);
if (conn_sock == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
setnonblocking(conn_sock);
/*设置新连接文件事件为读写事件*/
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
/*添加到epoll实例中,进行监控*/
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
&ev) == -1) {
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
}/*如果发生的事件不是在接收连接的套接字上面*/
else {
/*处理产生的新的连接的数据,例如,读取客户端写的数据,或者向客户端写数据*/
do_use_fd(events[n].data.fd);
}
}
}
}
- Linux man epoll_create
- Linux man epoll_ctl
- Linux man epoll_wait
- Unix 网络编程 卷I 套接字联网API