Linux 为什么要区分内核空间与用户空间?

Linux 操作系统的 IO 模型有哪几种?有啥区别?

常说的阻塞现象,到底是咋回事?

网络编程研发时,那块到底耗时最多,代码是否还有优化空间?

前几期的分享,我们站在编码视角去聊 Java IO,旨在理解与编码,本次从 Linux 操作系统层面了解一下 IO 模型,这样方能做到知其然,知其所以然。

01. 内核空间、用户空间


万事万物我们看到的皆是表象,操作系统也不例外。我们经常打交道的用户界面,是操作系统的外在表象,内核才是操作系统的内在核心。

内核,可以访问受保护的内存空间,拥有访问底层硬件设备的所有权限(比如读写磁盘文件,分配回收内存,从网络接口读写数据等等)。

为了内核的安全,操作系统将虚拟空间划分为内核空间(内核代码运行的地方)和用户空间(用户程序代码运行的地方)。内核空间和用户空间是隔离的,这样即使用户的程序崩溃了,内核也不受影响。

另外,用户程序不能直接操作内核,需要通过系统调用来与内核进行通信(应用程序通过内核提供的接口来完成访问)。

02. Socket 通信流程


Socket 通信流程应该不再陌生,本次分享着重剖析图中圈住的部分。

站在服务端的视角,对于一次 Socket 的数据读取操作流程,如图示意,网络数据到达网卡,数据先被拷贝到内核缓冲区中,然后从内核缓冲区拷贝到进程用户空间。

站在服务端的视角,当一个读操作发生时,稍微再细化一下,其实会经历两个阶段。

第一阶段:等待数据准备。

例如:recv() 等待数据,需要等待网络上的数据分组到达,然后被复制到内核的缓冲区。

第二阶段:将数据从内核缓冲区拷贝到用户空间。

例如:recv() 接收连接发送的数据后,需要把数据复制到内核缓冲区,再从内核缓冲区复制到进程用户空间。

一定记住这两个阶段,也正因为存在这两个阶段,Linux系统升级迭代中出现了五种网络 IO 模型。

03. Linux 网络 IO 模型


(一)阻塞 IO 模型 - Blocking IO

图解:当应用进程调用了 recv() 这个系统调用,内核就开始了 IO 的第一个阶段:准备数据。这个过程需要等待,也就是说数据被拷贝到操作系统内核的缓冲区中是需要一个过程的。而在用户进程这边,整个进程会被阻塞。当内核一直等到数据准备好了,它就会将数据从内核中拷贝到用户内存,然后内核返回结果,用户进程才解除阻塞的状态。

特点:在 IO 执行的两个阶段都被阻塞了。

场景:阻塞 Socket、Java BIO。适用并发较小的网络应用,并发较大的不适用,因为一个请求 IO 阻塞进程,就要为每个请求分配一个进程(线程)来响应,开销大。

(二)非阻塞 I/O 模型 - Non-Blocking IO

图解:当用户进程发出 recv() 操作时,如果内核中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个错误码。一旦内核中的数据准备好了,并且又再次收到了用户进程的系统调用,那么它马上就将数据拷贝到了用户内存,然后返回。

特点:用户进程需要不断的主动询问内核数据好了没有,进程轮询调用,消耗 CPU 资源。

场景:SOCKET 设置 NON BLOCKING 属性。支持并发量小,不用及时响应的网络应用。

(三)I/O多路复用 - IO multiplexing

在 Linux 内核代码迭代过程中,依次支持了 SELECT、POLL、EPOLL 三种多路复用的网络 I/O 模型。

IO 多路复用的的基本原理是指单个线程就可以同时处理多个网络连接。 具体实现是 SELECT、POLL、EPOLL这些函数,会不断的轮询所负责的所有 socket,当某个 socket 有数据到达了,就通知用户进程。

图解:以 select 为例,当用户进程调用了 select,那么整个进程会被阻塞,而此时,内核会监视所有 select 负责的 socket,当任何一个 socket 中的数据准备好了,select 就会返回。这个时候用户进程再调用 recv 操作,将数据从内核拷贝到用户进程。

特点:IO 多路复用是阻塞在 select,poll,epoll 这样的系统调用之上,而没有阻塞在真正的I/O系统调用(如recv());专一进程解决多个进程 IO 的阻塞问题,性能好,Reactor模式。

场景:Java NIO,Nginx。适用高并发服务应用开发,一个进程/线程响应多个请求。

(四)信号驱动 I/O - Signal driven IO

我们也可以用信号,让内核在描述字就绪时发送 SIGIO 信号通知我们,称这种模型为信号驱动I/O(signal-driven I/O)。

应用进程使用 sigaction 系统调用,预先告知内核,向内核注册这样一个函数,内核立即返回,应用进程可以继续执行,也就是说等待数据阶段应用进程是非阻塞的。内核在数据到达时向应用进程发送 SIGIO 信号,应用进程收到之后在信号处理程序中调用 recv() 将数据从内核复制到应用进程中。

(五)异步 I/O 模型 - Asynchronous IO

图解:应用进程执行 aio_read() 系统调用会立即返回,应用进程可以继续执行,不会被阻塞,内核会在所有操作完成之后向应用进程发送信号。

特点:不阻塞,一步到位。

景: Java 7 AIO、高性能服务器,高性能高并发。

异步 IO 模型,要求等待数据和数据拷贝操作的两个处理阶段上都不能等待(blocking),内核自行去准备好数据并将数据从内核缓冲区中复制到应用进程的缓冲区,再通知应用进程读操作完成了,然后应用进程再去处理。

遗憾的是,Linux 的网络 IO 模型中是不存在异步 IO 的,Linux 的网络 IO 处理的第二阶段总是阻塞等待数据 copy 完成的。

04. Linux 网络 IO 模型比较

上图已经把 Linux 中的 IO 模型归档的很到位,还是稍微总结一下。前四种 IO 模型都是同步 IO 模型,主要区别在于第一阶段的处理不同,第二阶段的处理是相同的,都是在数据从内核复制到用户空间时,进程阻塞于 recv() 调用。而异步 IO 模型的处理都是非阻塞的,用户进程将整个 IO 操作交由内核去完成,内核完成后会发送通知。

好了,今天就扯这么多,希望大家能够喜欢。

从 Linux 操作系统谈谈 IO 模型(终)的更多相关文章

  1. [转载] Linux五种IO模型

      转载:http://blog.csdn.net/jay900323/article/details/18141217     Linux五种IO模型性能分析   目录(?)[-] 概念理解 Lin ...

  2. Windows五种IO模型性能分析和Linux五种IO模型性能分析

    Windows五种IO模型性能分析和Linux五种IO模型性能分析 http://blog.csdn.net/jay900323/article/details/18141217 http://blo ...

  3. (转载) Linux五种IO模型

    转载:http://blog.csdn.net/jay900323/article/details/18141217     Linux五种IO模型及分析   目录(?)[-] 概念理解 Linux下 ...

  4. Linux 的 Socket IO 模型

    前言 之前有看到用很幽默的方式讲解Windows的socket IO模型,借用这个故事,讲解下linux的socket IO模型: 老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系. 他 ...

  5. 网络通信 --> Linux 五种IO模型

    Linux 五种IO模型 聊聊Linux 五种IO模型

  6. Linux五种IO模型(同步 阻塞概念)

    Linux五种IO模型 同步和异步 这两个概念与消息的通知机制有关. 同步 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.比如,调用readfrom系统调用时,必须等待IO操 ...

  7. linux下的IO模型---学习笔记

    1.linux文件系统和缓存 文件系统接口 文件系统-一种把数据组织成文件和目录的存储方式,提供了基于文件的存取接口,并通过文件权限控制访问. 存储层次 文件系统缓存 主存(通常时DRAM)的一块区域 ...

  8. 深入理解JAVA I/O系列六:Linux中的IO模型

    IO模型 linux系统IO分为内核准备数据和将数据从内核拷贝到用户空间两个阶段. 这张图大致描述了数据从外部磁盘向运行中程序的内存中移动的过程. 用户空间.内核空间 现在操作系统都是采用虚拟存储器, ...

  9. Linux五种IO模型性能分析

    1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步:       所谓同步,就是在发出一个功能调用时, ...

随机推荐

  1. frp 内网穿透访问内网Web服务

    ps:最近想要通过域名(公网)访问或者测试在本地搭建的 web 服务(不想在公网IP服务器上再部署个服务,也不想通过teamview等工具远程卡到爆!), 由于本地机器没有公网 IP,无法将域名解析到 ...

  2. 汇编语言-[bx]和loop指令和多个段

    5.1 [BX]和内存单元的描述 要完成描述一个内存单元,需要两种信息: 内存单元的地址: 可以用 [0] 表示一个内存单元, 0 表示单元的偏移地址,段地址默认在 ds 中: 同样也可以用 [bx] ...

  3. 前端---css3优化

    一.视差滚动(经过优化后的代码) .front::before { content: ''; position: fixed; // 代替background-attachment width: 10 ...

  4. GPS轨迹发生模拟器介绍

    GPS轨迹发生模拟器介绍 GPS信号模拟器能够模拟卫星信号运动轨迹,模拟GPS卫星导航系统的导航信号.GPS轨迹发生器可以模拟导航系统确定位置点如日期.时间.经度.纬度.海拔信息.速度等.GPS轨迹模 ...

  5. 【剑指Offer】简单部分每日五题 - Day 1

    今天开始更新leetcode上<剑指Offer>的题解,先从简单难度开始.预计按下列顺序更新: 简单难度:每日5题 中等难度:每日3题 困难难度:每日1题 17 - 打印从1到最大的n位数 ...

  6. web安全测试(上)

    前情提要: 公司的安全测试一直是安全部经理全权负责,测试部只做功能和自动化. 但是2019是公司业绩腾飞的一年,业务量越来越大了,安全部经理实在做不过来. 于是他给整个测试部培训<安全测试> ...

  7. 关于SDL的一些坑:找不到WinMain,不显示控制台,添加链接库等

    目录: 用CMake构建SDL时报错 Gcc添加链接库 Gcc找不到入口(WinMain) 让SDL启动时不带控制台窗口 用CMake构建SDL时报错 root@ubuntu:~/SDL# cmake ...

  8. 实操教程丨使用Pod安全策略强化K8S安全

    本文来自Rancher Labs 什么是Pod安全策略? Kubernetes Pod安全策略(PSP)是Kubernetes安全版块中极为重要的组件.Pod安全策略是集群级别的资源,用于控制Pod安 ...

  9. vue基础----组件通信($parent,$children)

    1.按照dom的父子级关系,在子组件中可以通过$parent 直接调用父组件的方法,也可得到父组件的属性. 2.在父组件中通过$childrens可以得到一个子组件数组,能够在父组件中调用子组件的方法 ...

  10. let和var在for循环中的不同表现

    var声明变量: var只有函数作用域,没有块级作用域 //函数作用域的表现 function test(){ var i =10; console.log(i); } test(); console ...