IO模型(epoll)--详解-01
写在前面
从事服务端开发,少不了要接触网络编程。epoll作为linux下高性能网络服务器的必备技术至关重要,nginx、redis、skynet和大部分游戏服务器都使用到这一多路复用技术。
本文会从网卡接收数据的流程讲起,串联起CPU中断、操作系统进程调度等知识;再一步步分析阻塞接收数据、select到epoll的进化过程;最后探究epoll的实现细节。目录:
一、从网卡接收数据说起
二、如何知道接收了数据?
三、进程阻塞为什么不占用cpu资源?
四、内核接收网络数据全过程
五、同时监视多个socket的简单方法
六、epoll的设计思路
七、epoll的原理和流程
八、epoll的实现细节
九、结论
一、从网卡接收数据说起
下图是一个典型的计算机结构图,计算机由CPU、存储器(内存)、网络接口等部件组成。了解epoll本质的第一步,要从硬件的角度看计算机怎样接收网络数据。

下图展示了网卡接收数据的过程。在①阶段,网卡收到网线传来的数据;经过②阶段的硬件电路的传输;最终将数据写入到内存中的某个地址上(③阶段)。这个过程涉及到DMA传输、IO通路选择等硬件有关的知识,但我们只需知道:网卡会把接收到的数据写入内存。
二、如何知道接收了数据?
了解epoll本质的第二步,要从CPU的角度来看数据接收。要理解这个问题,要先了解一个概念——中断。
计算机执行程序时,会有优先级的需求。比如,当计算机收到断电信号时(电容可以保存少许电量,供CPU运行很短的一小段时间),它应立即去保存数据,保存数据的程序具有较高的优先级。
一般而言,由硬件产生的信号需要cpu立马做出回应(不然数据可能就丢失),所以它的优先级很高。cpu理应中断掉正在执行的程序,去做出响应;当cpu完成对硬件的响应后,再重新执行用户程序。中断的过程如下图,和函数调用差不多。只不过函数调用是事先定好位置,而中断的位置由“信号”决定。

以键盘为例,当用户按下键盘某个按键时,键盘会给cpu的中断引脚发出一个高电平。cpu能够捕获这个信号,然后执行键盘中断程序。下图展示了各种硬件通过中断与cpu交互。

现在可以回答本节提出的问题了:当网卡把数据写入到内存后,网卡向cpu发出一个中断信号,操作系统便能得知有新数据到来,再通过网卡中断程序去处理数据。
三、进程阻塞为什么不占用cpu资源?
了解epoll本质的第三步,要从操作系统进程调度的角度来看数据接收。阻塞是进程调度的关键一环,指的是进程在等待某事件(如接收到网络数据)发生之前的等待状态,recv、select和epoll都是阻塞方法。了解“进程阻塞为什么不占用cpu资源?”,也就能够了解这一步。
为简单起见,我们从普通的recv接收开始分析,先看看下面代码:
//创建socket
int s = socket(AF_INET, SOCK_STREAM, );
//绑定
bind(s, ...)
//监听
listen(s, ...)
//接受客户端连接
int c = accept(s, ...)
//接收客户端数据
recv(c, ...);
//将数据打印出来
printf(...)
这是一段最基础的网络编程代码,先新建socket对象,依次调用bind、listen、accept,最后调用recv接收数据。recv是个阻塞方法,当程序运行到recv时,它会一直等待,直到接收到数据才往下执行。
工作队列
操作系统为了支持多任务,实现了进程调度的功能,会把进程分为“运行”和“等待”等几种状态。运行状态是进程获得cpu使用权,正在执行代码的状态;等待状态是阻塞状态,比如上述程序运行到recv时,程序会从运行状态变为等待状态,接收到数据后又变回运行状态。操作系统会分时执行各个运行状态的进程,由于速度很快,看上去就像是同时执行多个任务。
下图中的计算机中运行着A、B、C三个进程,其中进程A执行着上述基础网络程序,一开始,这3个进程都被操作系统的工作队列所引用,处于运行状态,会分时执行。

工作队列中有A、B和C三个进程
等待队列
当进程A执行到创建socket的语句时,操作系统会创建一个由文件系统管理的socket对象(如下图)。这个socket对象包含了发送缓冲区、接收缓冲区、等待队列等成员。等待队列是个非常重要的结构,它指向所有需要等待该socket事件的进程。

当程序执行到recv时,操作系统会将进程A从工作队列移动到该socket的等待队列中(如下图)。由于工作队列只剩下了进程B和C,依据进程调度,cpu会轮流执行这两个进程的程序,不会执行进程A的程序。所以进程A被阻塞,不会往下执行代码,也不会占用cpu资源。

ps:操作系统添加等待队列只是添加了对这个“等待中”进程的引用,以便在接收到数据时获取进程对象、将其唤醒,而非直接将进程管理纳入自己之下。上图为了方便说明,直接将进程挂到等待队列之下。
唤醒进程
当socket接收到数据后,操作系统将该socket等待队列上的进程重新放回到工作队列,该进程变成运行状态,继续执行代码。也由于socket的接收缓冲区已经有了数据,recv可以返回接收到的数据。
IO模型(epoll)--详解-01的更多相关文章
- (转)Linux下select, poll和epoll IO模型的详解
Linux下select, poll和epoll IO模型的详解 原文:http://blog.csdn.net/tianmohust/article/details/6677985 一).Epoll ...
- Linux下select, poll和epoll IO模型的详解
http://blog.csdn.net/tianmohust/article/details/6677985 一).Epoll 介绍 Epoll 可是当前在 Linux 下开发大规模并发网络程序的热 ...
- I/O模型之二:Linux IO模式及 select、poll、epoll详解
目录: <I/O模型之一:Unix的五种I/O模型> <I/O模型之二:Linux IO模式及 select.poll.epoll详解> <I/O模型之三:两种高性能 I ...
- (转载) Linux IO模式及 select、poll、epoll详解
注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案 ...
- (转)Linux IO模式及 select、poll、epoll详解
本文为转载,并作了部门调整.修改. [原文出处:https://segmentfault.com/a/1190000003063859] 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么 ...
- Linux IO模式及 select、poll、epoll详解(转)
同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. ...
- 网络通信 --> IO多路复用之select、poll、epoll详解
IO多路复用之select.poll.epoll详解 目前支持I/O多路复用的系统调用有 select,pselect,poll,epoll,I/O多路复用就是通过一种机制,一个进程可以监视 ...
- Linux IO模式以及select poll epoll详解
一 背景 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network ...
- 高并发网络编程之epoll详解(转载)
高并发网络编程之epoll详解(转载) 转载自:https://blog.csdn.net/shenya1314/article/details/73691088 在linux 没有实现epoll事件 ...
- Linux下的I/O复用与epoll详解(转载)
Linux下的I/O复用与epoll详解 转载自:https://www.cnblogs.com/lojunren/p/3856290.html 前言 I/O多路复用有很多种实现.在linux上,2 ...
随机推荐
- ojdbc15-10.2.0.4.0.jar maven 引用报错 Dependency 'com.oracle:ojdbc15:10.2.0.4.0' not found
ojdbc15-10.2.0.4.0.jar maven 引用报错 问题现象 在 Maven 工程中引用 ojdbc15-10.2.0.4.0.jar 报错,报错信息:Dependency 'com. ...
- Ubuntu上挂载源代码,docker容器中共享这个原代码,实现自动部署
https://www.jianshu.com/p/23465dc86d3e 地址 5.3. 挂载源代码 为了在宿主机上创建.NET Core 项目,这个时候我们就需要在Linux宿主机上安装.N ...
- django 模板里面for循环和if常用的方法
django 模板里面for循环常用的方法 {% for %} 允许我们在一个序列上迭代.与Python的for 语句的情形类似,循环语法是 for X in Y ,Y是要迭代的序列而X是在每一个特定 ...
- 怎么在 localhost 下访问多个 Laravel 项目,通过一个IP访问多个项目(不仅仅是改变端口哦)
server { listen 80; server_name blog.sweetsunnyflower.com; index index.html index.htm index.php; cha ...
- DirectX* 11 多线程渲染的性能、方法和实践
对于在 CPU 上运行的 PC 游戏,渲染通常是主要的性能瓶颈:多线程渲染是一种消除瓶颈的有效方法.本文研究了 DirectX* 11 多线程渲染的性能可扩展性,讨论了多线程渲染的两种基本方法,并介绍 ...
- linux查询日志命令总结
[背景] 排查线上环境问题,少不了去线上查日志.而使用什么命令,能快速准确地查到我们需要查找地日志信息,也是我们需要掌握的一项技能. [命令] Linux查看命令有多种:tail,head,cat,t ...
- PJzhang:ping命令的基本用法
猫宁!!! 参考链接:https://www.cnblogs.com/diantong/p/9626751.html http://aiezu.com/article/linux_ping_comma ...
- eve-ng
eve-ng eve-ng采用的是和web-iou一样的B/S模式,进步的地方是它只需拖动鼠标就可以搭建拓朴,比web-iou要直观. 此虚拟机已经集成了IOL的L2.L3以及vIOS的L ...
- 【Linux开发】内核模块简介
一. 摘要 这篇文章主要介绍了Linux内核模块的相关概念,以及简单的模块开发过程.主要从模块开发中的常用指令.内核模块程序的结构.模块使用计数以及模块的编译等角度对内核模块进行介绍.在Linux系统 ...
- mysql——插入、更新、删除数据(概念)
一.插入数据 1.为表的所有字段插入数据 -------------------------------------------------------------------------- (1)i ...