在Linux网络编程中,Linux内核2.6版本之前大多都是用 select() 作为非阻塞的事件触发模型,但是效率低,使用受限已经很明显的暴露了select()(包括poll)的缺陷,为了解决这些缺陷,epoll作为linux新的事件触发模型被创造出来。

一、epoll() 相对于 select() 的优点:

1、支持一个进程socket描述符(FD)的最大数目:

在select() 中,一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置(linux/posix_types.h 中定义:#define __FD_SETSIZE 1024)。表示 select() 最多同时监听1024个fd。对于那些需要支持上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样 会带来网络效率的下降;二是可以选择多进程的解决方案(传统的Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加 上进程间数据同步远比不上线程间同步高效,所以这也不是一种完美的方案。而 epoll() 支持的数目很大,等于系统最大打开的文件描述符数,这个文件描述符数跟内存有一定关系。

2、IO效率不随FD数目增加而线性下降:

select() 对事件的扫描是针对于所有创建的socket描述符进行的,也就是说,有多少个socket描述符,就需要遍历多少个句柄,所以IO效率是随描述符增加线性下降的;而epoll只遍历活跃的 socket 描述符,这是因为在内核实现中 epoll() 是根据每个 fd 上面的callback函数实现的。那么,只有“活跃”的socket才会主动的去调用 callback 函数,其他 idle 状态 socket 则不会。比如一个高速LAN环境,epoll并不比select/poll有什么效率,相 反,如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。

3、使用 mmap 加速内核与用户空间的消息传递

select() 事件触发后会将信息从内核拷贝到用户空间,这种拷贝就影响了效率。而 mmap 将内核与用户空间的内存映射到一块内存上,内核将消息捕获后放入该内存空间,用户无需拷贝直接可以访问,减少了拷贝次数,提高了效率。(mmap 将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。)

二、epoll() 工作模型:ET、LT

LT(level triggered)是缺省的工作方式,并且同时支持 block 和 no-block socket。在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的 fd 进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表。效率会低于ET触发,尤其在大并发,大流量的情况下。但是LT对代码编写要求比较低,不容易出现问题。LT模式服务编写上的表现是:只要有数据没有被获取,内核就不断通知你,因此不用担心事件丢失的情况。

ET (edge-triggered) 是高速工作方式,只支持no-block socket。 在这种模式下,当描述符从未就绪变为就绪时,内核就通过epoll告诉你,然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的 就绪通知,直到你做了某些操作而导致那个文件描述符不再是就绪状态(比如 你在发送,接收或是接受请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核就不会发送更多的通知(only once)。不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认。效率非常高,在并发,大流量的情况下,会比LT少很多 epoll() 的系统调用,因此效率高。但是对编程要求高,需要细致的处理每个请求,否则容易发生丢失事件的情况。

三、epoll() 的使用

1、epoll() 用到的所有函数都是在头文件 sys/epoll.h 中声明的

2、epoll 的三大函数:

  • int epoll_create(int size);
    创建一个 epoll 的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。
  • int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    epoll 的事件注册函数,它不同与 select() 是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。
    参数1 是 epoll_create() 的返回值;
    参数2 表示动作,用三个宏来表示:
      EPOLL_CTL_ADD   注册新的 fd 到 epfd 中
      EPOLL_CTL_MOD  修改已经注册的 fd 的监听事件
      EPOLL_CTL_DEL    从 epfd 中删除一个 fd 
    参数3 是需要监听的 fd ;
    参数4 是告诉内核需要监听什么事,struct epoll_event结构如下:
    struct epoll_event {
    __uint32_t events; /* Epoll events */
    epoll_data_t data; /* User data variable */
    };
    typedef union epoll_data {
    void *ptr;
    int fd;
    __uint32_t u32;
    __uint64_t u64;
    } epoll_data_t;

    结构体 epoll_event 被用于注册所感兴趣的事件和回传所发生待处理的事件,而epoll_data 联合体用来保存触发事件的某个文件描述符相关的数据。例如一个client连接到服务器,服务器通过调用 accept 函数可以得到于这个client对应的socket文件描述符,可以把这文件描述符赋给epoll_data的fd字段,以便后面的读写操作在这个文件描述符上进行。epoll_event 结构体的events字段是表示感兴趣的事件和被触发的事件,可以是以下几个宏的集合:
      EPOLLIN: 表示对应的文件描述符可以读;
      EPOLLOUT:表示对应的文件描述符可以写;
      EPOLLPRI:表示对应的文件描述符有紧急的数据可读;
      EPOLLERR:表示对应的文件描述符发生错误;
      EPOLLHUP:表示对应的文件描述符被挂断;
      EPOLLET: 表示对应的文件描述符有事件发生;
      EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。 
    epoll_ctl() 如果调用成功则返回0,不成功则返回-1。

  • int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    等待事件的产生,类似于 select() 调用。参数 events 用来从内核得到事件的集合,maxevents 表示每次能处理的事件数,这个 maxevents 的值不能大于创建 epoll_create() 时的size,参数 timeout 是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。最后 epoll_wait 返回发生事件数。

(转)Linux-epoll的更多相关文章

  1. Server Develop (六) Linux epoll总结

    Linux  epoll epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select.epoll最大的好处在于它不会随着监听fd数目的增长而降低效率.因为在内核中的sele ...

  2. Linux Epoll介绍和程序实例

    Linux Epoll介绍和程序实例 1. Epoll是何方神圣? Epoll但是当前在Linux下开发大规模并发网络程序的热门人选,Epoll 在Linux2.6内核中正式引入,和select类似, ...

  3. Linux epoll总结

    Linux epoll总结 Linux  epoll epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select.epoll最大的好处在于它不会随着监听fd数目的增长而降低 ...

  4. c/c++ linux epoll系列3 利用epoll_wait设置timeout时间长度

    linux epoll系列3 利用epoll_wait设置timeout时间长度 epoll_wait函数的第四个参数可以设置,epoll_wait函数的等待时间(timeout时间长度). 例子1, ...

  5. c/c++ linux epoll系列2 利用epoll_wait查看是否可以送信

    linux epoll系列2 利用epoll_wait查看是否可以送信 write函数本来是非阻塞函数,但是当缓存区被写满后,再往缓存区里写的时候,就必须等待缓存区再次变成可写,所以这是write就变 ...

  6. c/c++ linux epoll系列1 创建epoll

    linux epoll系列1 创建epoll 据说select和poll的弱点是,随着连接(socket)的增加,性能会直线下降. epoll不会随着连接(socket)的增加,性能直线下降. 知识点 ...

  7. Windows完成端口与Linux epoll技术简介

    收藏自:http://www.cnblogs.com/cr0-3/archive/2011/09/09/2172280.html WINDOWS完成端口编程1.基本概念2.WINDOWS完成端口的特点 ...

  8. Java网络编程和NIO详解6:Linux epoll实现原理详解

    Java网络编程和NIO详解6:Linux epoll实现原理详解 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO h ...

  9. 源码剖析Linux epoll实现机制及Linux上惊群

    转载:https://blog.csdn.net/tgxallen/article/details/78086360 看源码是对一个技术认识最直接且最有效的方式了,之前用Linux Epoll做过一个 ...

  10. Windows完成端口与Linux epoll技术简介(能看懂)

    WINDOWS完成端口编程1.基本概念2.WINDOWS完成端口的特点3.完成端口(Completion Ports )相关数据结构和创建4.完成端口线程的工作原理5.Windows完成端口的实例代码 ...

随机推荐

  1. word2016打开2007文档出错

    不知从何时起,我电脑上的一部分office文件打开时频频报错!!! 有一段时间发现,通过iis发布的网站上下载excel文件的时候,通过localhost下载的文件能够正常打开,但是通过IP和端口下载 ...

  2. mysql事务块处理

    begin ,rollback,commit .当然有的人用begin /begin work .推荐用START TRANSACTION 是SQL-99标准启动一个事务. start transac ...

  3. python selenum ---如何定位一组元素

    使用findElements方法定位一组对象 定位一组对象一般用于以下场景: · 批量操作对象,比如将页面上所有的checkbox都勾上 · 先获取一组对象,再在这组对象中过滤出需要具体定位的一些对象 ...

  4. memcache操作实例

    实例一: <?php //使用memcache类来操作 $mm = new Memcache(); $mm->addServer("192.168.70.114",11 ...

  5. makefile之origin函数

    origin 函数的作用是告诉你变量是哪里来的,其出生状况如何,他并不改变变量. 函数语法: $(origin ) 为变量的名字,而不是引用,所以一般没有"$"字符在前. orig ...

  6. 如何使用Photoshop(PS)将图片的底色变为透明

    很多时候需要将一张图片的底色变得透明.本文描述了使用PS将图片的一部分变得透明的方法.本例将一段艺术字的背景去掉,将背景透明的文字单独保存成图片,这样以后将这段文字粘贴到其他素材上的时候,就不用担心它 ...

  7. java删除递归文件夹及文件夹下文件

    public static void delUrlLocalFile(String urlPath) { File file = new File(urlPath); if(file.isDirect ...

  8. CDH 安装配置指南(Tarball方式)

    采用CDH Tarbal方式安装Hadoop集群. 1. 环境组件版本 组件名称 组件版本 用途 jdk 1.8 jdk-8u191-linux-x64 oracle jdk mysql mysql- ...

  9. TaskTracker学习笔记

    转自:http://blog.csdn.net/androidlushangderen/article/details/41477061 上次分析完JobTracker通过TaskScheduler如 ...

  10. 经典Mathematica函数大全

    转自:http://blog.renren.com/share/238323208/8426343822  Mathmatic 函数表  一.运算符及特殊符号 Line1; 执行Line,不显示结果  ...