epoll原理简述:epoll = 一颗红黑树 + 一张准备就绪句柄链表 + 少量的内核cache

select/poll 每次调用时都要传递你所要监控的所有socket给select/poll系统调用,这意味着需要将用户态的socket列表copy到内核态,如果以万计的句柄会导致每次都要copy几十几百KB的内存到内核态,非常低效。

调用epoll_create后,内核就已经在内核态开始准备帮你存储要监控的句柄了,每次调用epoll_ctl只是在往内核的数据结构里塞入新的socket句柄。

epoll向内核注册了一个文件系统,用于存储上述的被监控socket。当调用epoll_create时,就会在这个虚拟的epoll文件系统里创建一个file结点。当然这个file不是普通文件,它只服务于epoll。

epoll在被内核初始化时(操作系统启动),同时会开辟出epoll自己的内核高速cache区,用于安置每一个我们想监控的socket,这些socket会以红黑树的形式保存在内核cache里,以支持快速的查找、插入、删除。

这个内核高速cache区,就是建立连续的物理内存页,然后在之上建立slab层,简单的说,就是物理上分配好你想要的size的内存对象,每次使用时都是使用空闲的已分配好的对象。

调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。

通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已

这个准备就绪list链表是怎么维护的呢?当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。

所以,当一个socket上有数据到了,内核在把网卡上的数据copy到内核中后就来把socket插入到准备就绪链表里了。

【转】epoll的两种工作模式:

Epoll的2种工作方式-水平触发(LT)和边缘触发(ET)

假如有这样一个例子:

我们已经把一个用来从管道中读取数据的文件句柄(RFD)添加到epoll描述符

这个时候从管道的另一端被写入了2KB的数据

调用epoll_wait(2),并且它会返回RFD,说明它已经准备好读取操作

然后我们读取了1KB的数据

调用epoll_wait(2)……

Edge Triggered 工作模式:

如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait(2)之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。只有在监视的文件句柄上发生了某个事件的时候 ET 工作模式才会汇报事件。因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。在上面的例子中,会有一个事件产生在RFD句柄上,因为在第2步执行了一个写操作,然后,事件将会在第3步被销毁。因为第4步的读取操作没有读空文件输入缓冲区内的数据,因此我们在第5步调用 epoll_wait(2)完成后,是否挂起是不确定的。epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。最好以下面的方式调用ET模式的epoll接口,在后面会介绍避免可能的缺陷。

基于非阻塞文件句柄

只有当read(2)或者write(2)返回EAGAIN时才需要挂起,等待。但这并不是说每次read()时都需要循环读,直到读到产生一个EAGAIN才认为此次事件处理完成,当read()返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。

Level Triggered 工作模式:

相反的,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll(2),并且无论后面的数据是否被使用,因此他们具有同样的职能。因为即使使用ET模式的epoll,在收到多个chunk的数据的时候仍然会产生多个事件。调用者可以设定EPOLLONESHOT标志,在 epoll_wait(2)收到事件后epoll会与事件关联的文件句柄从epoll描述符中禁止掉。因此当EPOLLONESHOT设定后,使用带有

EPOLL_CTL_MOD标志的epoll_ctl(2)处理文件句柄就成为调用者必须作的事情。

struct epoll_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中为一个文件注册一个事件时,如果不需要什么额外的信息,只需要简单在epoll_data.fd = 当前文件的fd

(尽管这并不是必须的,在网上找到的几乎所有的博客都是这样写,呵呵)

但是当我们需要一些额外的数据的时候,就要用上void* ptr;

我们可以自定义一种类型,例如my_data,然后让ptr指向它,以后取出来的时候就能用了;

最后,记住union的特性,它只会保存最后一个被赋值的成员,所以不要data.fd,data.ptr都赋值;通用的做法就是给ptr赋值,fd只是有些时候为了演示或怎么样罢了

所以个人的想法是,其实epoll_data完全可以就是一个void*,不过可能为了一些简单的场景,才设计成union,包含了fd,u32,u64

linux中epoll原理,linux epoll epoll的原理相关推荐

  1. 关于Linux中的apt-get的相关操作及原理

    关于Linux中的apt-get的相关操作及原理 Linux下的apt-get指令与相关文件夹 apt-get是linux下的一种简便的安装和更新软件的方法,在装软件的时候常用的命令就是 sudo a ...

  2. linux中的根文件系统(rootfs的原理和介绍)

    一.什么是文件系统 文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构:即在存储设备上组织文件的方法.操作系统中负责管理和存储文件 ...

  3. 浅谈linux中的根文件系统(rootfs的原理和介绍)

    转自:点击打开 linux中有一个让很多初学者都不是特别清楚的概念,叫做"根文件系统".我接触linux前前后后也好几年了,但是对这个问题,至今也不是特别的清楚,至少没法给出一个很 ...

  4. linux中ftp用户,linux中怎么添加ftp用户

    Linux下创建用户是很easy的事情了,只不过不经常去做这些操作,时间久了就容易忘记.那么linux中怎么添加ftp用户,下面跟着学习啦小编一起来了解一下吧. linux中怎么添加ftp用户 在li ...

  5. linux中544进程,Linux基础--进程管理及其基本命令

    本文主要讲解Linux中进程管理的基本命令使用方法. 1. top命令 作用: 动态显示进程状态 格式:top [options] 常用选项: -d: 后面可以接秒数,就是整个程序画面更新的秒数, 默 ...

  6. 在Linux中head命令,Linux 中 head 命令实例

    原标题:Linux 中 head 命令实例 head命令将每个文件的前10行打印到标准输出.对于多个文件,在每个文件前面加上一个给出文件名的头.如果没有文件,或者文件为-,则读取标准输入. 如何使用h ...

  7. linux中top工具,Linux命令工具 top详解

    Linux命令工具 top详解 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.top是一个动态显示过程,即可以通过用户按键来不 ...

  8. 在linux中which命令,Linux 中 which 命令怎么用?

    在Linux中which命令的作用是在PATH变量指定的路径中,搜索某个系统命令的位置,并且返回第一个搜索结果,其用法为"which [文件...]",其参数有"-n&q ...

  9. linux中显示进程,linux中怎么显示所有进程

    Linuxlinux中显示所有进程下使用PS命令结合相关参数可以查看linux当前系统下的所有进程.那么linux中怎么显示所有进程呢?接下来大家跟着学习啦小编一起来了解一下的解决方法吧. linux ...

  10. linux中线程ptid,Linux 线程(1)线程创建

    1. 线程 线程是一个轻量化的进程,关于进程与线程的详细概念参见: 进程与线程 线程相比与进程而言,其控制和调度更加灵活,由于同一进程的多个线程共享同一地址空间,因此Text Segment.Data ...

最新文章

  1. 吴恩达深度学习课程deeplearning.ai课程作业:Class 1 Week 3 assignment3
  2. 一天搞定CSS:背景background--03
  3. 大话设计模式—代理模式
  4. vista 中php4, php5 共存
  5. 三维叉乘怎么算_3分钟做完这些题,你的CAD才算熟练
  6. Android Ubuntu 安装问题FAQ
  7. Hive 之 分析窗口函数
  8. 一看就懂ReactJS
  9. mac无法充电解决办法!快来get下吧!
  10. BZOJ 1055 [HAOI2008]玩具取名 DP
  11. 抖音企业号无需开发连接第三方系统
  12. Android 集成google地图 准备工作
  13. ping www.baidu.com时出现正在ping www.a.shifen.com
  14. Objective-c:写一份可测试的代码
  15. Java培训机构出来好找工作吗?
  16. 用JQuery写一个斗地主发牌器
  17. 打卡机的设计——基本功能
  18. pycharm-professional-2020.1下载与激活
  19. STS安装配置及写的一个springboot整合mybatis的小demo
  20. 计算机网络第二章--物理层

热门文章

  1. 2022版短视频去水印小程序
  2. mysql修改user_MySQL修改用户(RENAME USER)
  3. 数据库(数据库系统)大作业
  4. select动态绑定vue.js
  5. 游戏中集成unity admob视频广告中文教程
  6. [C++]jsoncpp中将整个Json::Value转成std::string或者把里面值转成string类型
  7. 深度学习中的梯度下降优化算法综述
  8. agios天河二号安装实践
  9. 【软考 系统架构设计师】软件工程⑤ 需求工程
  10. c++_1st par