开发高性能网络程序时,windows开发者们言必称iocp,linux开发者们则言必称epoll。大家都明白epoll是一种IO多路复用技术,可以非常高效的处理数以百万计的socket句柄,比起以前的select和poll效率高大发了。我们用起epoll来都感觉挺爽,确实快,那么,它到底为什么可以高速处理这么多并发连接呢?先简单回顾下如何使用C库封装的3个epoll系统调用吧。
  1. int epoll_create(int size);
  2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  3. int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
使用起来很清晰,首先要调用epoll_create建立一个epoll对象。参数size是内核保证能够正确处理的最大句柄数,多于这个最大数时内核可不保证效果。
epoll_ctl可以操作上面建立的epoll,例如,将刚建立的socket加入到epoll中让其监控,或者把 epoll正在监控的某个socket句柄移出epoll,不再监控它等等。epoll_wait在调用时,在给定的timeout时间内,www.linuxidc.com 当在监控的所有句柄中有事件发生时,就返回用户态的进程。从上面的调用方式就可以看到epoll比select/poll的优越之处:因为后者每次调用时都要传递你所要监控的所有socket给select/poll系统调用,这意味着需要将用户态的socket列表copy到内核态,如果以万计的句柄会导致每次都要copy几十几百KB的内存到内核态,非常低效。而我们调用epoll_wait时就相当于以往调用select/poll,但是这时却不用传递socket句柄给内核,因为内核已经在epoll_ctl中拿到了要监控的句柄列表。所以,实际上在你调用epoll_create后,内核就已经在内核态开始准备帮你存储要监控的句柄了,每次调用epoll_ctl只是在往内核的数据结构里塞入新的socket句柄。在内核里,一切皆文件。所以,epoll向内核注册了一个文件系统,用于存储上述的被监控socket。当你调用epoll_create时,就会在这个虚拟的epoll文件系统里创建一个file结点。当然这个file不是普通文件,它只服务于epoll。epoll在被内核初始化时(操作系统启动),同时会开辟出epoll自己的内核高速cache区,用于安置每一个我们想监控的socket,这些socket会以红黑树的形式保存在内核cache里,以支持快速的查找、插入、删除。这个内核高速cache区,就是建立连续的物理内存页,然后在之上建立slab层,简单的说,就是物理上分配好你想要的size的内存对象,每次使用时都是使用空闲的已分配好的对象。
  1. static int __init eventpoll_init(void)
  2. {
  3. ... ...
  4. /* Allocates slab cache used to allocate "struct epitem" items */
  5. epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),
  6. 0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC,
  7. NULL, NULL);
  8. /* Allocates slab cache used to allocate "struct eppoll_entry" */
  9. pwq_cache = kmem_cache_create("eventpoll_pwq",
  10. sizeof(struct eppoll_entry), 0,
  11. EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);
  12. ... ...
epoll的高效就在于,当我们调用epoll_ctl往里塞入百万个句柄时,epoll_wait仍然可以飞快的返回,并有效的将发生事件的句柄给我们用户。这是由于我们在调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。所以,epoll_wait非常高效。而且,通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已,如何能不高效?!那么,这个准备就绪list链表是怎么维护的呢?当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。所以,当一个socket上有数据到了,内核在把网卡上的数据copy到内核中后就来把socket插入到准备就绪链表里了。如此,一颗红黑树,一张准备就绪句柄链表,少量的内核cache,就帮我们解决了大并发下的socket处理问题。执行epoll_create时,创建了红黑树和就绪链表,执行epoll_ctl时,如果增加socket句柄,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断事件来临时向准备就绪链表中插入数据。执行epoll_wait时立刻返回准备就绪链表里的数据即可。最后看看epoll独有的两种模式LT和ET。无论是LT和ET模式,都适用于以上所说的流程。区别是,LT模式下,只要一个句柄上的事件一次没有处理完,会在以后调用epoll_wait时次次返回这个句柄,而ET模式仅在第一次返回。这件事怎么做到的呢?当一个socket句柄上有事件时,内核会把该句柄插入上面所说的准备就绪list链表,这时我们调用epoll_wait,会把准备就绪的socket拷贝到用户态内存,然后清空准备就绪list链表,最后,epoll_wait干了件事,就是检查这些socket,如果不是ET模式(就是LT模式的句柄了),并且这些socket上确实有未处理的事件时,又把该句柄放回到刚刚清空的准备就绪链表了。所以,非ET的句柄,只要它上面还有事件,epoll_wait每次都会返回。而ET模式的句柄,除非有新中断到,即使socket上的事件没有处理完,也是不会次次从epoll_wait返回的。

Linux下epoll如何实现高效处理百万句柄的相关推荐

  1. linux下epoll如何实现高效处理

    linux下epoll如何实现高效处理 作者 digoal 日期 2016-11-10 标签 Linux , 内核 , epoll , 网络编程 , 高并发 背景 本文转自 http://www.cn ...

  2. linux下Epoll实现简单的C/S通信

    From: http://blog.csdn.net/piaojun_pj/article/details/6103709 epoll的优点: 1.支持一个进程打开大数目的socket描述符(FD) ...

  3. epoll nio区别_高性能网络服务器编程:为什么linux下epoll是最好,Netty要比NIO.2好?...

    基本的IO编程过程(包括网络IO和文件IO)是,打开文件描述符(windows是handler,java是stream或channel),多路捕获(Multiplexe,即select和poll和ep ...

  4. linux socket epoll

    什么是epoll epoll是什么?按照man手册的说法:是为处理大批量句柄而作了改进的poll.当然,这不是2.6内核才有的,它是在2.5.44内核中被引进的(epoll(4) is a new A ...

  5. Windows下完成端口移植Linux下的epoll

         距离上一篇博客都已经半个多月了,这么多天一直在学习研究关于Windows的完成端口移植到Linux下epoll方面的内容.这两方面以前都没有太多的接触,所以花费了较长的时间.在连续加班两天后 ...

  6. 【流媒体服务器Mediasoup】 NodeJs与C++信令通信详解及Linux下管道通信的详解(五)

    目录 前言 匿名管道进程间通信 进程间管道 的创建与图解 MediaSoup中的管道创建 MediaSoup Channel的创建 NodeJs和 C++ 管道通信的过程 MediaSoup 消息确认 ...

  7. linux的open的非组赛,Linux下的非阻塞IO库epoll

    今天看到一篇文章,对于epoll讲解的非常生动清晰,转载收藏一下,原文请点击here. 生活中的一个例子 假设你在大学中读书,要等待一个朋友来访,而这个朋友只知道你在A号楼,但是不知道你具体住在哪里, ...

  8. Linux下select, poll和epoll IO模型的详解

    http://blog.csdn.net/tianmohust/article/details/6677985 一).Epoll 介绍 Epoll 可是当前在 Linux 下开发大规模并发网络程序的热 ...

  9. Windows 平台下面的IOCP技术 Linux下面Epoll 还有FreeBSD下面Kqueue的应用了。跨平台库行业里面最出名的莫过于ACE、ASIO(Boos公司)两大支持库支持IOCP

    http://wenku.baidu.com/view/4117460502020740be1e9b3c.html 游戏服务器集群 自从2003年开发VOIP Radius Server以及修改Gnu ...

最新文章

  1. 重型车辆盲区行为检查Behaviours – Heavy Vehicle Blind Spots
  2. 怎么主动发起话题_约会的时候,多聊这4个话题,女人才会失去抵抗力
  3. 阿里云服务器买了,如何建站呀?
  4. SSH分客户端openssh-client和openssh-server
  5. php tcp和udp的区别,HTTPS 和 HTTP、UDP 和 TCP 的区别
  6. the value of esp was not properly saved
  7. 升级后供电不足故障解决攻略
  8. java xwork_java-与休眠的Struts2 xwork类型转换
  9. Ubuntu中安装FastDFS
  10. Visio显示不完整
  11. input type=checkbox 前面有个可供打钩的小方框 HTML DOM Checkbox 对象
  12. SpringBoot中使用Hibernate Validator校验工具类
  13. vue 修改文件怎么启动_Jupyter Notebook如何修改启动时的默认文件路径(Windows系统)...
  14. Markdown 语法速查表
  15. visual studio怎么用_自从用了敏捷,天天在开会?4大Scrum会议如何才能有意义?...
  16. python三维转换教程_Python科学计算三维可视化【完结】
  17. 在飞桨平台做图像分类-1 制作基于飞桨的数据集|CSDN创作打卡
  18. python井字格游戏_python实现简单井字棋游戏
  19. POI导出word单元格合并
  20. 室内定位技术的应用及室内定位技术的种类-新导智能

热门文章

  1. linux 远程控制权限,总结一下linux远程控制方法
  2. git 分支合并_教你玩转Git-分支合并
  3. 机器学习实战笔记(Python实现)-01-机器学习实战
  4. Android模拟器Genymotion使用详解
  5. 使用 Binlog 和 Canal 从 MySQL 抽取数据
  6. 洗牌算法shuffle
  7. 鸟哥的Linux私房菜(服务器)- 第十二章、网络参数控管者: DHCP 服务器
  8. 深度学习(十三)caffe之训练数据格式
  9. Deep Learning论文笔记之(一)K-means特征学习
  10. Stanford UFLDL教程 逻辑回归的向量化实现样例