epoll接口介绍,epoll模型介绍+原理,接口和模型的关系,epoll优点(和select/poll进行对比)

10 篇文章 0 订阅

目录

epoll接口

epoll_create

size

返回值

epoll_wait

epfd

events

struct epoll_event

maxevent

timeout

返回值

epoll_ctl

epfd

op

fd

event

返回值

epoll模型

网络数据的处理

红黑树

就绪队列

回调函数 

总结

接口和模型的关系

epoll_create

epoll_ctl

epoll_wait

epoll优点(和select/poll的对比)

内核层面

用户层面


select和poll接口 -- 多路转接之select(fd_set介绍,参数详细介绍,优缺点),实现非阻塞式网络通信(代码+思路)_fdset大小-CSDN博客

多路转接之poll(接口介绍,struct pollfd介绍,实现原理,实现非阻塞网络通信代码)-CSDN博客

epoll接口

epoll_create

创建一个epoll模型

  • 用完之后,需要调用close()关闭

size

已经在linux2.6.8被废除了,参数不重要

  • 只要>0即可

返回值

  • 成功返回文件fd
  • 失败返回-1,并设置错误码

epoll_wait

等待 epoll 实例中的事件发生,获取已经就绪的文件及其上面的事件

epfd

epoll_create()的返回值

  • 该返回值本质上是epoll模型对应的文件描述符(后面细说)

events

输出型参数,返回已经就绪的文件fd和上面的事件

struct epoll_event

结构体中的两个字段:

  • 事件类型 -- 位图的形式,传递标记位(和poll中的events/revents是一样的,只是名字换成了EPOLL*)
  • 保存用户级数据(是联合体,可以是这些字段的其中之一) -- 方便我们后期得知是哪一个文件就绪,帮助我们进行事件处理(具体在代码中会体现)

maxevent

events数组的大小

  • 一次可以接收的最大事件数
  • 大小多少都可以,按需设置

timeout

超时时间,单位 -- 毫秒

  • 和poll中的作用一样

返回值

和select,poll中的一样,如果等待就绪事件成功,返回的是已就绪事件的个数

  • 该参数在select,poll中没什么作用,但在这里有大用

前面说了,events数组中会存储已就绪的fd及其事件信息

  • 所以,返回值对应着events数组中有效数据的个数
  • 可以用这个作为遍历数组的依据

其他两种情况,也与select/poll的返回值一样

  • 如果等待超时,返回0
  • 等待过程中有错误,返回<0的值

epoll_ctl

对系统要关心的文件/关心的事件做修改

  • 总之就是管理工作

epfd

依然是epoll_create()的返回值

op

选项,指定操作类型

  • 增/改/删

fd

要操作的文件fd

event

要操作的是文件上的哪个/哪些事件

  • 这里传递的是该结构的指针

返回值

  • 成功返回0
  • 失败返回-1,并设置错误码

select和poll都是用户自己维护了一个数组,来管理fd

os定期检查该进程的文件描述符表,查看是否有文件就绪

如果没有,则会被挂起,到等待队列中,到下一个时刻继续检查

所以,os需要主动检查是否就绪

epoll模型

网络数据的处理

当网络数据到达网卡时:

  • 网卡是个外设,不会自己对数据做处理,需要依靠os
  • 那os如何得知网卡上是否有数据?
  • 一旦数据就绪,会发生硬件中断
  • os为了处理中断 -> 查询中断向量表,执行注册好的处理程序 -> 将网卡数据读取到网卡驱动的数据链路层缓冲区(调用驱动层的方法,将数据交付到链路层)
  • 驱动层和链路层是对应的,因为网络是os的一部分:
  • 然后继续向上交付,直到传输层,就该轮到用户层通过系统调用读取数据了(可以选择调用recv/read阻塞等待数据到来,或是使用select/poll/epoll等机制,数据到来后再通知上层来读)

为了支持epoll的特性,os会维护两个结构:

红黑树

os会在内部维护一棵红黑树

  • 以fd为键值
  • 每个结点代表要关注的一个文件及其相关事件(对应select/poll中用户自己维护的数组)

就绪队列

如果红黑树中的某个结点上有事件就绪(对应某文件上有事件就绪),就把它链入到就绪队列中

  • 是形成一个新的结点,而不是直接把结点拿过去 (一个结点可以存在于多个结构中)

以上操作由os自发完成

除了两个结构,os还提供了回调函数 

回调函数 

网卡允许os注册回调函数

当链路层有数据(以sk_buff的形式存在)就绪,就会调用该函数,该函数的作用:

所以,之后用户只需要从就绪队列中拿取已经就绪的事件即可

以上三套机制,叫做epoll模型

总结

所以,epoll_create所做的创建epoll模型,说的就是要创建这两个内核数据结构

  • 这些结构会被统一管理起来,因为可能会存在多套epoll模型(只要调用多次epoll_create就能做到)
  • 如何组织起来?
  • 就绪队列的头结点,红黑树的根结点的指针放在一块就好了,回调函数只要注册在链路层就不用管了
  •  当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体

这套模型如何被用户层使用呢?

  • 因为linux中"一切皆文件"的理念,我们把它也当做文件,创建一个struct file与它关联,分配到进程的文件描述符表中
  • 只要知道fd,就能找到file结构体,里面有指针指向epoll模型,就能操作epoll相关结构

这就是为什么epoll_create返回的是一个fd,因为它底层是以struct file被管理:

所以,epoll和前面学的两个方案(select,poll)是完全不一样的

  • 内核为了支持epoll会专门设计结构
  • 而那俩只是简单的遍历fd表,结构需要自己维护

接口和模型的关系

epoll_create

  • 创建出上面介绍的两个结构(红黑树和就绪队列),挂接到文件结构体上
  • 将file结构添加到调用该函数的进程的文件描述符表中
  • 最后返回给用户层fd

epoll_ctl

  • 根据epfd参数,查找当前进程fd表,从而找到epoll模型对应的file结构
  • file和epoll模型一一对应,所以可以找到红黑树
  • 而ctl的三种操作 -- 增删改,就是对红黑树的操作

epoll_wait

  • 和ctl一样,有epfd,就可以找到epoll模型结构,这里用到的是就绪队列
  • events是输出型参数,wait操作会将就绪队列中的一定量元素(就绪的文件及其上面的事件)放入数组中
  • 如果队列中元素个数>数组大小(也就是wait中的maxevents参数),那就下次再说(在下一次操作时,再拿取剩下的已就绪信息)

epoll优点(和select/poll的对比)

内核层面

数据从接收 到 通知我们 的过程中,是一路被回调过来的

  • 也就是事件驱动,不需要os主动轮询检测

os检测是否就绪

  • 时间复杂度是O(1),因为只需要判断就绪队列是否为空
  • 而不像来select/poll,需要遍历文件描述符表,检查每个fd的状态

os获取就绪事件并传给用户层

  • 时间复杂度为O(n) ,因为os只需遍历就绪队列,将队列中结点拷贝到用户层即可(wait中传入的events数组中)
  • 另外两种机制也是O(n),os需要更新fd_set集合

用户层面

用户层获取就绪事件

  • wait拿到的events数组,本身就存放了连续的就绪事件
  • 所以,用户层不需要遍历+判断(是否是有效fd),直接拿就行
  • 也就是,epoll的遍历不会有无效操作

可以关注的文件上的事件无上限

  • 因为本质上这些事件都是红黑树上的结点,而红黑树本身可以扩容
  • 所以,上限在于内存是否足够,而不在于epoll机制
  • epoll里的红黑树正对应select/poll里用户维护的数组,数组是有上限的,虽然也可以手动让它扩容,但总归是不方便,而且一旦数量过多,因为遍历效率低成本高,所以扩容太多也不好,这里就没有这个缺点,因为从机制上就不一样

epoll接口使用 -- epoll接口使用 -- 非阻塞式网络io(仅读事件)-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值