在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. 解决Jquery Ajax提交 服务器端接收中文乱码问题

    看到有朋友说到用post提交方式解决,我指定了methord="post",仍然解决不了, 说一下解决办法,客户端进行编码,服务器端解码, 客户端:var where = esca ...

  2. 全面进攻python之前回顾下自己近三个月的自学之路

    人生是在一直试错的过程中成长起来的.这句话貌似很有道理,但回顾了下自己近三个月python自学学习之路,又觉得自己对这句话又有了新的看法------行动之前必须要有正确的选择,这样做错了才能成长. 2 ...

  3. C#通过webbrowser控件与javascript交互

    1.C#里调用控件里面网页的js函数     //调用JavaScript的messageBox方法,并传入参数     object[] objects = new object[1];     o ...

  4. 大型站点技术架构PDF阅读笔记(一):

    1.数据库读写分离: 2.系统吞吐量和系统并发数以及系统响应时间之间的关系: 3.系统负载的概念: 4.反向代理的概念: 5.使用缓存来读取数据: 6.利用cookie来记录session: 利用co ...

  5. python学习之find()

    定义: find() 方法检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内,如果包含子字符串返回开始的索引值,否则返回-1. 语法 ...

  6. Jquery学习笔记(3)--注册验证

    嗯哼,验证用户名,密码,重复密码,手机号,邮箱.提交时全部进行验证,通过才跳转. <!DOCTYPE html> <html lang="en"> < ...

  7. 使用SWT技术的跨平台移动应用开发库Tabris

    1. http://developer.eclipsesource.com/tabris/ 2. 多平台.原生程序级别的性能 3. 开源/教育性的项目免费,意思就是商业项目收费 4. 目标,让懂jav ...

  8. Ehcache2 的配置(不使用配置文件)

    EhCache是一个开放源码的,基于标准的高速缓存系统. 网上关于EhCache的使用配置很多,但是一般是基于配置文件的.但是实际应用中.我们可能需要动态的管理缓存,这时候单纯配置文件就不够用了. 所 ...

  9. mongodb数据库安装与卸载

    此处以centos下monggodb3.4版本安装为例,可参考官网安装教程 步骤如下: 1.配置mongodb ym源 vi /etc/yum.repos.d/mongodb-org-3.4.repo ...

  10. 企业Shell面试题5:解决DOS攻击生产案例

    企业Shell面试题5:解决DOS攻击生产案例 写一个Shell脚本解决DOS攻击生产案例. 请根据web日志或者或者网络连接数,监控当某个IP并发连接数或者短时内PV达到100(读者根据实际情况设定 ...