epoll通过下面3个epoll系统调用为用户提供服务。

(1)epoll_create系统调用

epoll_create在C库中的原型如下:

int epoll_create(int size);

epoll_create返回一个句柄,之后epoll的使用都将依靠这个句柄来标识。参数size是告诉epoll所要处理的大致事件数目。不再使用epoll时,必须调用close关闭句柄。

注:size参数只是告诉内核这个epoll对象会处理的事件大致数目,而不是能够处理的事件的最大个数。在Linux最新的一些内核版本的实现中,这个size参数没有任何意义。

(2)epoll_ctl系统调用

epoll_ctl在C库中的原型如下:

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epoll_ctl向epoll对象中添加、修改或者删除感兴趣的事件,返回0表示成功,否则返回-1,此时需要根据errno错误码判断错误类型。epoll_wait方法返回的事件必然是通过epoll_ctl添加到epoll中的。

参数epfd是epoll_create返回的句柄,而op参数的意义见表:

op的取值 意义
EPOLL_CTL_ADD 添加新的事件到epoll中
EPOLL_CTL_MOD 修改epoll中的事件
EPOLL_CTL_DEL 删除epoll中的事件

第3个参数fd是待监测的连接套接字,第4个参数是在告诉epoll对什么样的事件感兴趣,它使用了epoll_event结构体,如下是epoll_event的定义:

struct epoll_event {

  __uint32_t events;

  epoll_data_t data;

};

events的取值如下:

events取值 意义
EPOLLIN 表示对应的连接上有数据可读(TCP连接的远端主动关闭连接,也相当于可读事件,因为需要处理发送来的FIN包)
EPOLLOUT 表示对应的连接上可写入数据发送(主动向上游服务器发起非阻塞的TCP连接,连接建立成功的事件相当于可写事件)
EPOLLRDHUP 表示TCP连接的远端关闭或半关闭连接
EPOLLPRI 表示对应的连接上有紧急的数据需要读取
EPOLLERR 表示对应的连接发生错误
EPOLLHUP 表示对应的连接被挂起
EPOLLET 表示将触发方式设置为边缘触发ET,系统默认为水平触发LT
EPOLLONESHOT 表示对这个事件智处理一次,下次需要处理时需重新加入epoll

而data成员是一个epoll_data联合,其定义如下:

typedef union epoll_data {

  void *ptr;

  int fd;

  uint32_t u32;

  uint64_t u64;

}epoll_data_t;

可见,这个data成员还与具体的使用方式有关。

(3) eplll_wait系统调用

epoll_wait在C库中的原型如下:

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

收集在epoll监控的事件中已经发生的事件,如果epoll中没有任何一个事件发生,则最多等待timeout毫秒后返回。epoll_wait的返回值表示当前发生的事件个数,如果返回0,则表示本次调用中没有事件发生,如果返回-1,则表示出现错误,需要检查errno错误码判断错误类型。

第1个参数epfd是epoll的描述符。

第2个参数events则是分配好的epoll_event结构体数组,epoll将会把发生的事件复制到events数组中(events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮我们在用户态中分配内存。内核这种做法效率很高)。

第3个参数maxevents表示本次可以返回的最大事件数目,通常maxevents参数与预分配的events数组的大小是相等的。

第4个参数timeout表示在没有检测到事件发生时最多等待事件,单位毫秒,如果timeout为0,则表示epoll_wait在rdllist为空时,立刻返回,不会等待。

epoll有两种工作模式:LT(水平触发)模式和ET(边缘触发)模式。默认情况下epoll采用LT模式工作,这时可以处理阻塞和非阻塞套接字,上表中EPOLLET表示可以将一个事件改为ET模式。ET模式的效率比LT模式的效率高,它只支持非阻塞套接字。ET模式与LT模式的区别在于:

当一个新的事件到来时,ET模式下当然可以从epoll_wait调用中获取到这个事件,可是如果这次如果没有把这个事件对应的套接字缓冲区处理完,在这个套接字没有新的事件再次到来时,在ET模式下是无法再次从epoll_wait调用中获取这个事件的;

而LT模式则相反,只要一个事件对应的套接字缓冲区还有数据,就总能从epoll_wait中获取这个事件。

因此在LT模式下开发基于epoll的应用要简单一些,不太容易出错,而在ET模式下事件发生时,如果没有彻底地将缓冲区数据处理完,则会导致缓冲区中的用户请求得不到响应。

默认情况下Nginx是通过ET模式使用epoll的。

最新文章

  1. Redis初探
  2. java集合类的学习(一)
  3. 初识Linux-4
  4. 枚举类型Enum
  5. 清除行内元素之间HTML空白的几种解决方案
  6. POJ 2240 Arbitrage(floyd)
  7. Unix中$$、$@、$#、$*的意思
  8. POJ 3630 Phone List Trie题解
  9. 使用PF_PACKET和SOCK_RAW发送自己定义type以太网数据包
  10. 深度爬取之rules
  11. linux下的Shell编程(4)特殊的变量和占位符
  12. RabbitMQ 入门【精+转】
  13. PHP的会话控制
  14. [python]Generators
  15. Sketch webView方式插件开发技术总结
  16. java 里面的 native 方法
  17. 如何通过 Terminal 设置截图存储的位置
  18. CyclicBarrier循环屏障相关
  19. WorldWind源码剖析系列:网络下载类WebDownload
  20. sql-case when 条件1 then 取值1 when 条件2 then 取值2 else 取值3 end

热门文章

  1. HBase与Zookeeper的关系
  2. Linux环境mysql快速备份及迁移
  3. Java POI 导出EXCEL经典实现
  4. DEDECMS:解决无法上传图片(在后台插入图片时提示类型不允许)
  5. UI中的事件系统EventSystem
  6. CentOS 7 部署redis
  7. 2019牛客国庆集训派对day2
  8. ACwing 258. 石头剪子布
  9. .NET 5学习笔记(10)——Entity Framework Core之切换SQLServer和SQLite
  10. Atlas 分表功能