[关闭]
@LIUHUAN 2016-05-06T21:03:17.000000Z 字数 3476 阅读 1205

epoll 相关

Linux c/c++


1.epoll_create调用

  1. int epoll_create(int size);
  2. int epoll_create1(int flags);
  • 第一个函数epoll_create调用是比较常用的调用,第二个调用是改进版本。内核版本在2.9以及之后才能够使用。
  • 调用成功的返回值,是一个文件描述符(非负整数),指向一个epoll实例,这个文件描述符代表这后续对于epoll相关接口的引用。需要在使用结束后调用close关闭文件描述符。
  • 调用出现错误的返回值是-1,并可以在全局变量error中查看错误信息。
  • 第一个调用的参数size是,调用者在后续使用epoll添加感兴趣的文件描述符个数的大小,这个是一个给系统初次分配epoll监控文件描述符数据结构的内存空间的一个参考值,但是如果后来调用者,监听的事件超过这个范围,那么系统会额外的分配空间的。
    总的来说这个值只是操作系统的参考值。
  • epoll_create1参数是一个文件描述符标志,如果为0那么和 epoll_create(0)一样。

2 epoll_ctl调用

2.1函数原型

  1. #include <sys/epoll.h>
  2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

2.2参数说明

2.2.1 event参数

结构体定义

  1. typedef union epoll_data {
  2. void *ptr;
  3. int fd;
  4. uint32_t u32;
  5. uint64_t u64;
  6. } epoll_data_t;
  7. struct epoll_event {
  8. uint32_t events; /* Epoll events */
  9. epoll_data_t data; /* User data variable */
  10. };
  • epoll_event中events变量为事件发生的类型,可以是下面提到的事件类型EPOLLIN,EPOLLOUT,EPOLLHDUP,EPOLLPRI,EPOLLERR,EPOLLHUP,EPOLLET,EPOLLONESHOT,EPOLLWAKEUP中的一种,具体的参见下面的事件类型说明。
  • data为一个联合体,可以根据不同的事件,来表示用户数据内容。例如可以是一个文件描述符。

2.2.2 fd参数

fd为需要监控的文件描述符。在这里是根据这个文件描述符对后面的event结构进行操作的。具体见下面的op参数.

2.2.3 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上面发生的文件事件操作。

2.2.4 epdf参数

epfd为epoll_create 或者epoll_create1函数调用的返回值,实际为一个文件描述符,指向epoll实例。epoll系统操作都是通过这个文件描述符来进行的。

2.3返回值

  • 调用成功返回0
  • 失败返回-1,并置error错误信息。

3 epoll_wait调用

3.1函数原型

  1. #include <sys/epoll.h>
  2. int epoll_wait(int epfd, struct epoll_event *events,
  3. int maxevents, int timeout);
  4. int epoll_pwait(int epfd, struct epoll_event *events,
  5. int maxevents, int timeout,const sigset_t *sigmask);

3.2参数说明

3.2.1 timeout参数

  • timeout参数指定了在没有事件发生的时候epoll_wait调用阻塞的毫秒数(milliseconds)。
  • 如果把这个值设置为-1,那么在没有事件发生时,这个调用会永远的阻塞下去。
  • 如果timeout=0那么epoll_wait会检查监控的事件是否发生,然后立刻返回。
  • 上面指的事件,可以包含监控的文件事件,也可以是信号中断事件。

3.2.2 maxevent参数

  • maxevent,是一次调用epoll_wait可以返回有监控事件发生的最大个数。
  • 例如监控的事件中在某一时刻可能有20个发生了,但是如果这个时候maxevent=10,那么只会返回10个发生的事件。

3.2.3 events参数

  • events表示的是一个struct epoll_event数组,存放的是某个时刻发生事件的结构体
  • 可以在epoll_wait调用结束之后,来访问这个结构体里面的内容例如fd来处理发生的文件事件。

3.2.4 epfd参数

  • epfd为epoll_create函数返回的文件描述符。epoll实例。

3.3返回值

  • 没有任何事件发生,或者超时返回0。
  • 出现错误返回-1,并设置error错误信息。
  • 返回监控事件发生的个数。

4.使用方法

下面是一个处理多个客户端连接的服务端程序,可以根据这个大体的框架和自己的情况进行修改。

  1. #include<stdio.h>
  2. #include<unistd.h>
  3. #include<sys/epoll.h>
  4. #define MAX_EVENTS 10
  5. int main (int argc,char* argv[] ) {
  6. struct epoll_event ev, events[MAX_EVENTS];
  7. int listen_sock, conn_sock, nfds, epollfd;
  8. /* Code to set up listening socket, 'listen_sock',
  9. (socket(), bind(), listen()) omitted */
  10. /*创建epoll实例*/
  11. epollfd = epoll_create1(0);
  12. if (epollfd == -1) {
  13. perror("epoll_create1");
  14. exit(EXIT_FAILURE);
  15. }
  16. /*设置epoll_event,关联到epoll实例*/
  17. ev.events = EPOLLIN;
  18. ev.data.fd = listen_sock;
  19. /*注册listen_sock到epoll实例*/
  20. if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
  21. perror("epoll_ctl: listen_sock");
  22. exit(EXIT_FAILURE);
  23. }
  24. for (;;) {
  25. /*监控事件的发生,-1表示检查监控的事件后立即返回*/
  26. nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
  27. if (nfds == -1) {
  28. perror("epoll_wait");
  29. exit(EXIT_FAILURE);
  30. }
  31. /*遍历返回的事件,对事件进行处理*/
  32. for (n = 0; n < nfds; ++n) {
  33. /*如果是发生在接收连接的套接字上,那么接受客户端连接,并监控新建的连接文件事件*/
  34. if (events[n].data.fd == listen_sock) {
  35. conn_sock = accept(listen_sock,
  36. (struct sockaddr *) &local, &addrlen);
  37. if (conn_sock == -1) {
  38. perror("accept");
  39. exit(EXIT_FAILURE);
  40. }
  41. setnonblocking(conn_sock);
  42. /*设置新连接文件事件为读写事件*/
  43. ev.events = EPOLLIN | EPOLLET;
  44. ev.data.fd = conn_sock;
  45. /*添加到epoll实例中,进行监控*/
  46. if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
  47. &ev) == -1) {
  48. perror("epoll_ctl: conn_sock");
  49. exit(EXIT_FAILURE);
  50. }
  51. }/*如果发生的事件不是在接收连接的套接字上面*/
  52. else {
  53. /*处理产生的新的连接的数据,例如,读取客户端写的数据,或者向客户端写数据*/
  54. do_use_fd(events[n].data.fd);
  55. }
  56. }
  57. }
  58. }

4.参考内容

  • Linux man epoll_create
  • Linux man epoll_ctl
  • Linux man epoll_wait
  • Unix 网络编程 卷I 套接字联网API
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注