1. epoll概述

相对于 select() 和 poll() 来说,epoll 更加灵活,没有描述符限制。epoll 使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的 copy 只需一次。

2. epoll的接口函数

为了在后面更加方便理解epoll的原理,我们先从接口函数开始下手:

  1. epoll_create
    创建epoll句柄
    函数声明:int epoll_create(int size)
    参数:size用来告诉内核这个监听的数目一共有多大。
    返回值:返回创建了的epoll句柄。
    当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

  2. epoll_ctl
    将被监听的描述符添加到epoll句柄或从epool句柄中删除或者对监听事件进行修改。
    函数申明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event*event);
    参数:
    epfd: epoll_create()的返回值
    op:表示要进行的操作,其值分别为:
    EPOLL_CTL_ADD: 注册新的fd到epfd中;
    EPOLL_CTL_MOD: 修改已经注册的fd的监听事件;
    EPOLL_CTL_DEL: 从epfd中删除一个fd;
    fd:需要操作/监听的文件句柄
    event:是告诉内核需要监听什么事件,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 */
};  

events可以是以下几个宏的集合:
- EPOLLIN:触发该事件,表示对应的文件描述符上有可读数据。(包括对端SOCKET正常关闭);
- EPOLLOUT:触发该事件,表示对应的文件描述符上可以写数据;
- EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
- EPOLLERR:表示对应的文件描述符发生错误;
- EPOLLHUP: 表示对应的文件描述符被挂断;
- EPOLLET:将EPOLL设为边缘触发(EdgeTriggered)模式,这是相对于水平触发(Level Triggered)来说的。
- EPOLLONESHOT: 只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。

  1. epoll_wait
    等侍注册在epfd上的socket fd的事件的发生,如果发生则将发生的sokct fd和事件类型放入到events数组中。
    函数原型:int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    参数:
    epfd:由epoll_create 生成的epoll文件描述符
    events:用于回传代处理事件的数组
    maxevents:每次能处理的最大事件数
    timeout:等待I/O事件发生的超时毫秒数,-1相当于阻塞,0相当于非阻塞。一般用-1即可。

3. epoll实现机制

当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体,这个结构体中有两个成员与epoll的使用方式密切相关。eventpoll结构体如下所示:

struct eventpoll{..../*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件*/struct rb_root  rbr;/*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/struct list_head rdlist;....
};

内部用了一个红黑树记录添加的socket,用了一个双向链表接收内核触发的事件。

然后我们通过epoll_ctl方法向epoll对象中添加进来的事件。

这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是lgn,其中n为树的高度)。

而所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当相应的事件发生时会调用这个回调方法。这个回调方法在内核中叫ep_poll_callback,它会将发生的事件添加到rdlist双链表中。

在epoll中,对于每一个事件,都会建立一个epitem结构体,如下所示:

struct epitem{struct rb_node  rbn;//红黑树节点struct list_head    rdllink;//双向链表节点struct epoll_filefd  ffd;  //事件句柄信息struct eventpoll *ep;    //指向其所属的eventpoll对象struct epoll_event event; //期待发生的事件类型
}

当调用epoll_wait检查是否有事件发生时,只需要检查eventpoll对象中的rdlist双链表中是否有epitem元素即可。如果rdlist不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户。

4. epoll的工作模式

ET(EdgeTriggered):高速工作模式,只支持no_block(非阻塞模式)。在此模式下,当描述符从未就绪变为就绪时,内核通过epoll告知。然后它会假设用户知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到某些操作导致那个文件描述符不再为就绪状态了。(触发模式只在数据就绪时通知一次,若数据没有读完,下一次不会通知,直到有新的就绪数据)

LT(LevelTriggered):缺省工作方式,支持blocksocket和no_blocksocket。在LT模式下内核会告知一个文件描述符是否就绪了,然后可以对这个就绪的fd进行IO操作。如果不作任何操作,内核还是会继续通知!若数据没有读完,内核也会继续通知,直至设备数据为空为止!

二者的差异在于level-trigger模式下只要某个socket处于readable/writable状态,无论什么时候进行epoll_wait都会返回该socket;而edge-trigger模式下只有某个socket从unreadable变为readable或从unwritable变为writable时,epoll_wait才会返回该socket。

从本质上讲:与LT相比,ET模型是通过减少系统调用来达到提高并行效率的。

Linux网络编程 之 IO复用epoll(十)相关推荐

  1. Linux网络编程---I/O复用模型之epoll

    https://blog.csdn.net/men_wen/article/details/53456474 Linux网络编程-I/O复用模型之epoll 1. epoll模型简介 epoll是Li ...

  2. Linux网络编程---I/O复用模型之select

    https://blog.csdn.net/men_wen/article/details/53456435 Linux网络编程-I/O复用模型之select 1. IO复用模型 IO复用能够预先告知 ...

  3. Linux网络编程---I/O复用模型之poll

    https://blog.csdn.net/men_wen/article/details/53456474 Linux网络编程-I/O复用模型之poll 1.函数poll poll系统调用和sele ...

  4. Linux网络编程——I/O复用函数之epoll

    https://blog.csdn.net/lianghe_work/article/details/46544567 一.epoll概述 epoll 是在 2.6 内核中提出的,是之前的 selec ...

  5. linux网络编程系列-select和epoll的区别

    select和epoll属于I/O多路复用模型,用于持续监听多个socket,获取其IO事件. select(轮询) 该模型轮询各socket,不管socket是否活跃,随着socket数的增加,性能 ...

  6. 第4章 Linux网络编程 24.端口复用

    目录 端口复用 查看网络相关信息的命令 端口复用 端口复用最常用的用途是: 防止服务器重启时之前绑定的端口还未释放 (2msl) 程序突然退出而系统没有释放端口 查看网络相关信息的命令 netstat ...

  7. Linux网络编程——I/O复用之select详解

    https://blog.csdn.net/lianghe_work/article/details/46506143 一.I/O复用概述 I/O复用概念: 解决进程或线程阻塞到某个 I/O 系统调用 ...

  8. Linux网络编程——I/O复用之poll函数

    一.回顾前面的select select优点: 目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点 select缺点: 1.每次调用 select(),都需要把 fd 集合从用户态拷贝到内核 ...

  9. Linux网络编程 之 IO多路复用select(八)

    1. IO多路复用的概念 I/O多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. 2. select接口 #include & ...

最新文章

  1. 【03】Spark分析日志实例
  2. C++纯虚函数和抽象类
  3. silverlight textblock 自动换行
  4. 一文读懂 AVL 树
  5. [css] 如果css文件过大时,如何异步加载它?
  6. 脏牛Linux本地提权漏洞复现(CVE-2016-5195、Linux、Android、提权)
  7. Java读取URL到字符串
  8. AS/400开发经验点滴(六)如何制作下拉菜单
  9. 使用PHP与PostgreSQL开发的相关配置
  10. idea中有些类明明在jar包里有,但是却搜不到
  11. 计算机专业交互式教学课件制作,简易交互式课件的制作
  12. 2021-08-21Verilog三段式状态机的写法,标准示例和仿真。
  13. 使用Java和eclipse进行XML文件解析20180812_韩信之
  14. bt 介绍以及 bt 种子的hash值(特征值)计算
  15. 【堆栈溢出】堆栈溢出_liangchaoxi的IT博客_新浪博客
  16. 考研英语到底该如何复习?
  17. 本科计算机考研考英语,2016考研必需知道的10件事
  18. 设置linux kernel 日志打印方法
  19. 在微软官方网站”满速”下载Windows10最新系统镜像方法。
  20. docker安装和启动

热门文章

  1. 【玩转cocos2d-x之三十三】游戏嵌入Webview网页
  2. Android QEMU 高速管道
  3. OpenShift 与 OpenStack:让云变得更简单
  4. C++ STL : SGI-STL空间配置器源码剖析
  5. Socket之UDP服务器【Python】
  6. 搞定系统设计 03:系统设计面试的答题框架
  7. KCL:声明式的云原生配置策略语言
  8. LiveVideoStackCon 2022 上海站 专题抢先看
  9. 十一资讯 | 字节跳动进军汽车云;Twitch被黑;Facebook宕机;Netfilx收购游戏公司……...
  10. JVM之方法区Mothed Area