开发高性能网络程序时。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时间内,当在监控的全部句柄中有事件发生时,就返回用户态的进程。

从上面的调用方式就能够看到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实现将GPS定位信息上报到服务器

    操作系统:CentOS 开发板:fl2440 开发模块:A7(GPS/GPRS),RT3070(无线网卡) ********************************************** ...

  2. 比较一下Linux下的Epoll模型和select模型的区别

    一. select 模型(apache的常用) 1. 最大并发数限制,因为一个进程所打开的 FD (文件描述符)是有限制的,由 FD_SETSIZE 设置,默认值是 1024/2048 ,因此 Sel ...

  3. Linux下巧用my.cnf,mysql连接服务器不需要输入账号密码信息

    Linux下每次用mysql连接连接服务器,常常用如下方式: [root@localhost ~]# mysql -hlocalhost -uroot -p11111 每次都输入用户名,密码,多折腾人 ...

  4. 简单通讯聊天 群聊功能 Windows下的客户端 Linux下的epoll服务器

    1 服务器代码  Linux eclipse C++ //======================================================================= ...

  5. mongodb 之linux下安装、启动、停止、连接

    今天在linux上面安装了mongodb 1.下载linux的mongodb 2.在目录usr/local下创建文件夹mongodb,把安装包解压到该文件夹中 # mkdir mongodb # ta ...

  6. centos linux下配置固定ip,方便xshell连接

    如何给centos linux设置固定ip地址,设置Linux系统的固定IP地址 首先wmware打开虚拟机 打开xshell6连接虚拟机(比较方便,这里默认设置过Linux的ip,只是不固定,每次打 ...

  7. Linux下基于Erlang的高并发TCP连接压力实验

    1.实验环境: 联想小型机: 操作系统:RedHat Enterprise LinuxServer release6.4(Santiago) 内核版本号:Linux server1 2.6.32-35 ...

  8. Linux 下操作Mysql指令的总结 远程连接的设置

    参考博客:https://www.cnblogs.com/liaocheng/p/4243579.html (常用命令) https://www.cnblogs.com/zhangzhu/archiv ...

  9. 【Linux下Hadoop-eclipse-plus-3.2.0】编译Hadoop连接eclipse的插件遇见的一系列错误,崩溃的操作

    2019-09-02 23:35:22 前言:首先,我想吐槽下自己,居然花费了4到5个夜晚和中午的时间来做这件事情,直到刚才才顺利解决,我也挺佩服自己的! 我在这个过程中参考其他人的博客,非常感谢他们 ...

随机推荐

  1. js中时钟表盘

    1.js时钟表盘 代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  2. C语言入门100题,考算法的居多

    入门题,考算法的居多,共同学习! 1. 编程,统计在所输入的50个实数中有多少个正数.多少个负数.多少个零. 2. 编程,计算并输出方程X2+Y2=1989的所有整数解. 3. 编程,输入一个10进制 ...

  3. c++中的类型转换--reinterpret_cast

    原文链接:  浅析c++中的类型转换--reinterpret_cast转换 reinterpret_cast作用为: 允许将任何指针转换为任何其他指针类型. 也允许将任何整数类型转换为任何指针类型以 ...

  4. linux nohup & 简单使用

    线上通常nohup配合&启动程序,同时免疫SIGINT和SIGHUP信号,从而保证程序在后台稳定运行 & 1.后台运行,输出默认到屏幕 2.免疫SIGINT信号,比如Ctrl+c不会杀 ...

  5. MySql(四)Select条件查询

    select条件查询的格式如下: SELECT 查询列表FROM 表名WHERE 筛选条件:123456根据筛选条件可以分为以下几类: 按照条件按表达式进行筛选 常用条件运算符如下:> .< ...

  6. vue过渡 & 动画---进入/离开 & 列表过渡

    (1)概述 Vue 在插入.更新或者移除 DOM 时,提供多种不同方式的应用过渡效果.包括以下工具: 在 CSS 过渡和动画中自动应用 class 可以配合使用第三方 CSS 动画库,如 Animat ...

  7. 洛谷——P2007 魔方

    P2007 魔方 常神牛家的魔方都是3*3*3的三阶魔方,大家都见过. 模拟即可: #include<iostream> #include<cstdio> #include&l ...

  8. ZOJ - 3993 - Safest Buildings (数学)

    参考:https://blog.csdn.net/KuHuaiShuXia/article/details/78408194 题意: 描述了吃鸡刷圈的问题,给出楼的坐标点,和两次刷圈的半径R和r,现在 ...

  9. 调用subprocess调用shell命令时屏蔽标准输出

    import os, subprocessp = subprocess.Popen(args, stdout = subprocess.PIPE,stderr = subprocess.STDOUT)

  10. 洛谷 2633 BZOJ 2588 Spoj 10628. Count on a tree

    [题解] 蜜汁强制在线... 每个点开一个从它到根的可持久化权值线段树.查询的时候利用差分的思想在树上左右横跳就好了. #include<cstdio> #include<algor ...