目录

  • 基本使用方法
    • step1:创建epollfd
    • step2:将fd绑定到epollfd
    • step3:调用epoll_wait检测事件
    • epoll_wait与poll、select区别所在
  • 水平触发与边缘触发

基本使用方法

step1:创建epollfd

  • 创建一个epollfd,若epoll_create调用成功,则返回一个非负值的epollfd,否则返回-1
/* Creates an epoll instance.  Returns an fd for the new instance.The "size" parameter is a hint specifying the number of filedescriptors to be associated with the new instance.  The fdreturned by epoll_create() should be closed with close().  */
extern int epoll_create (int __size) __THROW;

step2:将fd绑定到epollfd

有了epollfd之后,我们有三种需求:
1、将需要检测事件的其他fd绑定到这个epollfd上
2、修改一个已经绑定到epollfd的fd的事件类型
3、在不需要的时候将fd从epollfd上解绑
都需要依托函数epoll_ctl完成:

/* Manipulate an epoll instance "epfd". Returns 0 in case of success,-1 in case of error ( the "errno" variable will contain thespecific error code ) The "op" parameter is one of the EPOLL_CTL_*constants defined above. The "fd" parameter is the target of theoperation. The "event" parameter describes which events the calleris interested in and any associated user data.  */
extern int epoll_ctl (int __epfd, int __op, int __fd,struct epoll_event *__event) __THROW;

__epfd:即epollfd
__op:操作类型,有三种EPOLL_CTL_ADDEPOLL_CTL_MODEPOLL_CTL_DEL。分别对应着在epollfd上添加、修改、移除fd,当为EPOLL_CTL_DEL时,__event参数忽略,置NULL
__fd:需要备操作的fd
__event:一个epoll_event结构体的地址
具体结构如下:

// 在64位操作系统下,大小为8 byte
typedef union epoll_data
{void *ptr;int fd;uint32_t u32;uint64_t u64;
} epoll_data_t;struct epoll_event
{uint32_t events;   /* 需要检测的fd事件标志 */epoll_data_t data; /* 用户自定义的数据*/
} __EPOLL_PACKED;

返回值
调用成功,返回0;
调用失败,返回-1,通过errno错误码可以获取具体的错误原因。

step3:调用epoll_wait检测事件

/* Wait for events on an epoll instance "epfd". Returns the number oftriggered events returned in "events" buffer. Or -1 in case oferror with the "errno" variable set to the specific error code. The"events" parameter is a buffer that will contain triggeredevents. The "maxevents" is the maximum number of events to bereturned ( usually size of "events" ). The "timeout" parameterspecifies the maximum wait time in milliseconds (-1 == infinite).This function is a cancellation point and therefore not marked with__THROW.  */
extern int epoll_wait (int __epfd, struct epoll_event *__events,int __maxevents, int __timeout);

__events:一个epoll_event结构数组的首地址,是一个输出参数,在函数调用成功后,在events中存放的是与就绪事件相关的epoll_event结构体数组。
__maxevents:数组元素个数
__timeout:超时时间,单位为ms
返回值:调用成功返回有事件的fd数量,若返回0,表示超时。若返回-1,表示调用失败。
使用示例如下:

    while (true) {epoll_event epollEvents[1024];int n = epoll_wait(epollfd, epollEvents, 1024, 1000);if (n < 0) {if (errno == EINTR) {// 被信号中断 重试continue;} else {// 出错 退出break;}} else if (n == 0) {// 超时,继续重试continue;} else {// 处理事件for (size_t i = 0; i < n; i++) {if (epollEvents[i].events & EPOLLIN) {// 处理可读事件} else if (epollEvents[i].events & EPOLLOUT) {// 处理可写事件} else if (epollEvents[i].events & EPOLLERR) {// 处理出错事件}}}}

epoll_wait与poll、select区别所在

在第二讲中演示了select的基本使用方式:C++网络编程快速入门(二):Linux下使用select演示简单服务端程序
select和epoll底层机制一样,所以这里只看select。
可以发现调用完select之后,需要在原来的clientfds数组中遍历,然后加条件判断是否是有事件的。
而epoll_wait调用完之后是直接返回一个筛选过后的有事件的events数组。
所以:
在fd数量比较多但是某段时间内的就绪事件fd数量较少时,epoll_wait函数更加高效。
也就是epoll模型更适合用在socket连接数量较大而活跃的连接较少的情景下

水平触发与边缘触发

epoll具有两种模式:边缘触发模式(Edge Trigger,ET)和水平触发模式(Level Trigger,LT)。
区别在于:
1、LT:一个事件只要有,就会一直触发
2、ET:一个事件从无到有,才会触发
以socket读事件为例:
水平模式下,只要socket上有未读完的数据,就会一直产生EPOLLIN事件。
边缘模式下,socket上每新来一次数据就会触发一次,如果上一次触发后未将socket上的数据读完,也不会再触发,除非再新来一次数据。
以socket写事件为例:
水平模式下,只要socket上TCP窗口一直不饱和,就会一直触发EPOLLOUT事件。
边缘模式下,只有TCP窗口由不饱和变成饱和 或者 再一次变成不饱和,才会触发EPOLLOUT事件。
这对于编程的启示是:
1、对于非阻塞socket,如果epoll使用边缘模式检测事件可读,那么一旦触发,一定要一次性把socket上数据收取干净,即循环调用recv函数直到recv出错

bool recvEtMode()
{// 每次只收取256个字节char buf[256];while (true) {int nRecv = ::recv(clientfd, buf, 256, 0);if (nRecv == -1) {if (errno == EWOULDBLOCK) {return true;} else if (errno == EINTR) {continue;} else {return false;}}else if (nRecv == 0) {// 对端关闭了socketreturn false;} else {inputBuffer.add(buf, (size_t)nRecv);}}return true;
}

2、如果是水平模式,可以根据业务一次性收取固定字节数
下面总结一下两者在编码上需要注意的地方:
1、LT模式下,读事件触发后可以按需收取想要的字节数,不用把本次数据收取干净;
ET模式下,读事件必须把数据收取干净,因为我们不一定再有机会收取数据了。
2、LT模式下,不需要写事件时一定要及时移除,避免不必要地触发且浪费CPU资源。
ET模式下,写事件触发后,如果还需要下一次的写事件触发来驱动任务(例如发送上次剩余的数据),则我们需要继续注册一次检测可写事件
3、LT会导致多次触发,ET优点是触发次数少

C++网络编程快速入门(四):EPOLL模型使用相关推荐

  1. C++网络编程快速入门(二):Linux下使用select演示简单服务端程序

    目录 select参数解释 select使用规范 select使用缺点 基本流程 实例代码 通信效果演示 往期文章 select参数解释 extern int select (int __nfds, ...

  2. 【Socket网络编程进阶与实战】------ Socket网络编程快速入门

    前言 本篇博客主要是分享,socket网络编程进阶与实践☞socket网络编程快速入门 一.聊一聊Socket 学习目标与收获

  3. Windows下C语言网络编程快速入门

    C语言的学习,一般的方式是,先学C,然后是C++,最好还要有汇编语言和微机原理基础,然后才是Visual C++.这样的方式,对学习者来说,要花费很多时间和耐力.而在学校教学中,也没有时间深入学习Wi ...

  4. Winsock网络编程快速入门

     一.基本知识 1.Winsock,一种标准API,一种网络编程接口,用于两个或多个应用程序(或进程)之间通过网络进行数据通信.具有两个版本: Winsock 1: Windows CE平台支持. ...

  5. C++网络编程快速入门(三):阻塞与非阻塞式调用网络通信函数

    目录 阻塞与非阻塞定义 send与recv connect 一些问题 为什么要将监听socket设置为非阻塞 阻塞与非阻塞定义 阻塞模式指的是当前某个函数执行效果未达预期,该函数会阻塞当前的执行线程, ...

  6. C++网络编程快速入门(一):TCP网络通信基本流程以及基础函数使用

    目录 流程概述 服务器端代码实现 客户端代码实现 函数和结构讲解 sockaddr_in和sockaddr socket : 创建一个socket连接 bind :绑定地址以及端口号问题 流程概述 客 ...

  7. Python3网络爬虫快速入门实战解析

    Python3网络爬虫快速入门实战解析 标签: python网络爬虫 2017-09-28 14:48 6266人阅读 评论(34) 收藏 举报 分类: Python(26) 作者同类文章X 版权声明 ...

  8. Java NIO 非阻塞网络编程快速入门

    NIO 非阻塞网络编程快速入门 案例: 编写一个 NIO 入门案例,实现服务器端和客户端之间的数据简单通讯(非阻塞) 目的:理解 NIO 非阻塞网络编程机制 import java.net.InetS ...

  9. pdf python 3.7编程快速入门 潘中强_无python基础,这些书籍可以帮您快速入门。

    利用Python进行数据分析> 定 价:119 元 作者:韦斯·麦金尼(Wes McKinney)著;徐敬一译 ISBN:9787111603702 出 版 社:机械工业出版社 学习Python ...

最新文章

  1. java 往文件写值,java文件读写
  2. 蓝桥杯- 图形显示(java)
  3. python Modbus基础
  4. webService学习5:Eclipse的TCP/IP工具
  5. 结对-结对编项目作业名称-需求分析
  6. Docker学习总结(67)—— 取代 Dockerfile 的新型镜像构建技术 Buildpacks 详解
  7. 新手tiktok怎么做?海外tiktok怎么赚钱!
  8. c++ 函数模板_C++函数模板(泛型编程)
  9. 小组文化——洗洗睡了的故事
  10. c++多线程——数据共享
  11. iso安装器_mac怎么装双系统|mac电脑安装双系统教程
  12. 【路径规划】基于matlab GUI改进的DWA算法机器人动态避障路径规划【含Matlab源码 1271期】
  13. WPS2005 For Linux 序列号
  14. 死锁产生的原因及解决方法
  15. java qq截图,qq截屏-qq截屏下载-javaweb下载站
  16. 51单片机实现出租车计价器
  17. 单片机——BH1750光照传感器篇
  18. 一个IT实习生的感悟
  19. 曹操为何杀死神医华佗?
  20. 系统调用的概念及原理

热门文章

  1. java成绩查询_JavaWeb项目第三次总结_成绩查询的实现
  2. java 获取mysql链接_Java中如何获取mysql连接的3种方法总结
  3. 8g可用 安装内存16g_同样是16g内存,为啥都选两条8G,不选16G单条,这难道有啥讲究?...
  4. 【HBuilder】手机App推送至Apple App Store过程
  5. elementUI vue 编辑中的input的验证残留清除
  6. 反序列化 还是记一下吧
  7. MySQL 快速定位性能问题
  8. HDU3415 Max Sum of Max-K-sub-sequence
  9. coursera 《现代操作系统》 -- 第五周 同步机制(1)
  10. Cocos2d-JS项目之UI界面的优化