epoll怎么实现的

epoll 可以说是编写高性能服务端程序必不可少的技术,在介绍 epoll 之前,我们先来了解一下 多路复用I/O 吧。

多路复用I/O

多路复用I/O:是指内核负责监听多个 I/O 流,当任何一个 I/O 流处于就绪状态(可读或可写)时都会通知进程,以便可以处理该 I/O 流上的数据。如 图1 所示:

图片

如 图1 所示,内核负责监听多个 I/O 流,当某些 I/O 流变为就绪状态,内核会把这些 I/O 流添加到就绪队列中,然后通知进程处理就绪队列中的 I/O 流。

与传统的阻塞型 I/O 相比,多路复用 I/O 的优点是可以同时监听多个 I/O 流,并且会把就绪的 I/O 流告知进程。

epoll原理

介绍完多路复用 I/O,接下来开始介绍我们的主角:epoll

在 Linux 系统中,有多种多路复用 I/O 的实现,比如 select 和 poll 等。而 epoll 也是多路复用 I/O 一种实现,与 select 和 poll 相比,epoll 在性能上有较大的提升。

红黑树

epoll 内部使用红黑树来保存所有监听的 socket,红黑树是一种平衡二叉树,添加和查找元素的时间复杂度为 O(log n),其结构如 图2 所示:

图片

epoll 通过 socket 句柄来作为 key,把 socket 保存在红黑树中。如 图2 所示,每个节点中的数字代表着 socket 句柄。

把监听的 socket 保存在红黑树中的目的是,为了在修改监听 socket 的读写事件时,能够通过 socket 句柄快速找到对应的 socket 对象。

就绪队列

另外,epoll 还维护着一个就绪队列,当 epoll 监听的 socket 状态发生改变(变为可读或可写)时,就会把就绪的 socket 添加到就绪队列中。如 图3 所示:

图片

当 socket 从网络中获取到数据后,会发生通知给 epoll,epoll 会将当前 socket 添加到就绪队列中,并且唤醒等待中的进程(也就是调用 epoll_wait 的进程)。

当 socket 状态发生变化时,会调用 ep_poll_callback 函数来通知 epoll,我们来看看这个函数的处理过程:

static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key)
{...struct epitem *epi = ep_item_from_wait(wait);struct eventpoll *ep = epi->ep;...// 1) 把 socket 添加到就绪队列中list_add_tail(&epi->rdllink, &ep->rdllist);is_linked:// 2) 唤醒调用 epoll_wait() 而被阻塞的进程if (waitqueue_active(&ep->wq))wake_up_locked(&ep->wq);...return 1;
}
 

ep_poll_callback 函数的意图很清晰,主要完成两个工作:

  • 把就绪的 socket 添加到就绪队列中。

  • 唤醒调用 epoll_wait 函数而被阻塞的进程。

当进程被唤醒后,就会从就绪队列中,把就绪的 socket 复制到用户提供的数组中。如 图4 所示:

图片

如 图4 所示,在调用 epoll_wait 时需要提供一个 events 数组来存储就绪的 socket。当 epoll_wait 返回后,用户就可以从events 数组中获取到就绪的 socket,并可对其进行读写操作。

总结

本文主要通过图解的方式大概介绍了 epoll 的原理,但很多实现的细节只能通过阅读源码来了解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

xxx

ota的升级及下载转载于:https://www.cnblogs.com/bigben0123/p/4221520.html

C#中yield return用法

转载:http://www.jb51.net/article/54810.htm http://www.cnblogs.com/HunterWei/archive/2012/06/13/csharpyieldreturn.html http://www.cnblogs.com/nankezhishi/archive/2009/03/20/1418086.html http://kb.cnblogs.com/page/42580/ 简单地说,当希望…

SICP~计算机程序的构造和解释~ 1.12 c++实现

题目&#xff1a; 采用递归计算过程计算出帕斯卡三角形的各个元素。 row:0 11 1 12 1 2 13 1 3 3 14 1 4 6 4 15 . . . . . .col: 0 1 2 3 4 //c //递归 #include<iostream> using namespace std;int pascaler(int row ,int col){ int value;…

模板参数自动推导

class Dummy { public:template<typename PA, typename PB>void test(PA res, PB b){} }; int main() {Dummy dummy;dummy.test(1, 2); //不指定类型&#xff0c;根据参数自动推导dummy.test<int, int>(1, 2); //指定类型 } class Dummy { p…

平衡树以及AVL树

平衡树是计算机科学中的一类数据结构。 平衡树是计算机科学中的一类改进的二叉查找树。一般的二叉查找树的查询复杂度是跟目标结点到树根的距离&#xff08;即深度&#xff09;有关&#xff0c;因此当结点的深度普遍较大时&#xff0c;查询的均摊复杂度会上升&#xff0c;为了更…

esmini接入外部ego车控制

1. esmini 在Server.cpp中提供了外部控制ego车的方式&#xff0c;以UDP的方式接收外部数据然后驱动ego运动。为了开启UDP数据接收线程&#xff0c;只需要命令行增加--server参数即可。 2. ScenarioGateway 类中保存了所有车辆的当前数据&#xff0c;UDP线程接收到数据后需要调…

【Python笔记】异常处理

1 什么是异常 异常即是一个事件&#xff0c;该事件会在程序执行过程中发生&#xff0c;影响了程序的正常执行。一般情况下&#xff0c;在Python无法正常处理程序时就会发生一个异常。异常是Python对象&#xff0c;表示一个错误。 当Python脚本发生异常时我们需要捕获处理它&…

java 判断两个数是否异号

java 整型int占4个字节32位&#xff0c;两个数异或后移动31位判断结果&#xff0c;如果是1则异号&#xff0c;如果是0则同号 1 public class ShowEnviromentViarible {2 3 public static void main(String[] args) {4 int num1 1;5 int num2 -1;6 …

法线和法线贴图

法线和法线贴图 1、法线无处不在&#xff0c;这是图形学基础中的基础。 2、法线贴图&#xff0c;凹凸图&#xff0c;位移图等等&#xff0c;在图形学历史上有着比较重要的位置&#xff0c;在很多图形学的架构中都有应用&#xff0c;典型的例如延迟渲染架构。 法线 法线&…

css3制作滚动按钮

1&#xff0c;中间圆点用到css3的gradient属性 2&#xff0c;运动用到css3的transition属性 3&#xff0c;需要写各个浏览器的兼容 代码如下 1 <!DOCTYPE html>2 <html lang"en">3 <head>4 <meta charset"UTF-8">5 <ti…

Unicode、UTF-8、UTF-16

计算机起源于美国&#xff0c;上个世纪&#xff0c;他们对英语字符与二进制位之间的关系做了统一规定&#xff0c;并制定了一套字符编码规则&#xff0c;这套编码规则被称为ASCII编码 ASCII 编码一共定义了128个字符的编码规则&#xff0c;用七位二进制表示 ( 0x00 - 0x7F ), …

在linux命令行中直接执行php命令

有时候用浏览器调试太麻烦&#xff0c;想在linux命令下直接执行php代码 php -r echo 0500; 转载于:https://www.cnblogs.com/wangkongming/p/4236138.html

顶点缺失问题

1. 发送缓冲区过小&#xff0c;模型过大&#xff0c;接收端接收缓冲区太小&#xff0c;并且接收数据与数据处理在一个线程&#xff0c;导致接收速度过慢。最终造成&#xff0c;发送缓冲区被撑爆&#xff0c;数据丢失。 2. U3D端对单个mesh的顶点限制在了65000个。 3. 对于超过…

LoadRunner中Action的迭代次数的设置和运行场景中设置

LoadRunner中Action的迭代次数的设置和运行场景中设置 LoadRunner是怎么重复迭代和怎么增加并发运行的呢&#xff1f;另外&#xff0c;在参数化时&#xff0c;对于一次压力测试中均只能用一次的资源应该怎么参数化呢&#xff1f;就是说这些资源用了一次就不能在用了的。&#x…

IE11 全新的F12开发者工具

我讨厌debug&#xff0c;相信也没多少开发者会喜欢。但是当代码出错之后肯定是要找出问题出在哪里的。不过网页开发的时候遇到 BUG 是一件再正常不过的事情了&#xff0c;我们不能保证自己的代码万无一失&#xff0c;于是使用浏览器的开发者工具调试是我们解决问题最快捷的方法…

OpenXLSX 中文字段读取问题

在读取excel的时候发现有些中文字段无法读取&#xff0c;通过把excel文件解压后对比发现&#xff0c;正常读取和不 能正常读取的中文字段在sharedString.xml中存储的格式有差异&#xff0c;取其中一个字段&#xff0c;如下图&#xff1a; 正常读取的 不能读取的 对比可以看到…

时间格式化需要注意点不可使用本地时间

var compareTime DateTime.Now; var start DateTime.Parse(string.Format("{0:u}", compareTime)); var end DateTime.Parse(compareTime.ToString()); Console.WriteLine(string.Format("时间格式正确{0}", startend)); 各位猜猜&#xff0c;输出是什么…

MFC 窗口置顶

SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); SetWindowPos(NULL, 300, 150, 80, 40, SWP_SHOWWINDOW);