一、什么是IO?

我们都知道Liux世界里、一切皆文件、而文件是什么呢?文件就是一串二进制流而已、不管socket、还是FIFO、管道、终端、对我们来说、一切都是文件、一切都是流、在信息交换的过程中、我们都是对这些流进行数据的收发操作、简称为I/O操作(input and output)、往流中读出数据、系统调用read、写入数据、系统调用write、不过话说回来了、计算机里有这么多的流、我怎么知道要操作哪个流呢?做到这个的就是文件描述符、即通常所说的fd、一个fd就是一个整数、所以对这个整数的操作、就是对这个文件(流)的操作、我们创建一个socket、通过系统调用会返回一个文件描述符、那么剩下对socket的操作就会转化为对这个描述符的操作、不能不说这又是一种分层和抽象的思想。

二、IO交互

通常用户进程中的一个完整IO分为两个阶段

用户空间<------------->内核空间、

内核空间<------------->设备空间、

内核空间中存放的是内核代码和数据、而进程的用户空间中存放的是用户程序的代码和数据、不管是内核空间还是用户空间、它们都处于虚拟空间中、Linux使用两级保护机制:0级供内核使用、3级供用户程序使用、操作系统和驱动程序运行在内核空间、应用程序运行在用户空间、两者不能简单地使用指针传递数据、因为Linux使用的虚拟内存机制、其必须通过系统调用请求kernel来协助完成IO动作、内核会为每个IO设备维护一个缓冲区、用户空间的数据可能被换出、当内核空间使用用户空间指针时、对应的数据可能不在内存中。

对于一个输入操作来说、进程IO系统调用后、内核会先看缓冲区中有没有相应的缓存数据、没有的话再到设备中读取、因为设备IO一般速度较慢、需要等待、内核缓冲区有数据则直接复制到进程空间、

所以、对于一个网络输入操作通常包括两个不同阶段:

(1)等待网络数据到达网卡 –&gt; 读取到内核缓冲区

(2)从内核缓冲区复制数据 –&gt; 用户空间

IO有内存IO、网络IO和磁盘IO三种、通常我们说的IO指的是后两者。

阻塞IO(blocking I/O)

我们运行一段服务端socket监听程序(典型的阻塞IO场景):

我们知道server.accept是阻塞的,如果没有连接连上来就会一直等待不会往下执行。

同时我们是道reader.readLIne也是阻塞的,不写入东西也不会往下执行。所以我们new了个线程,可以达到同时监听多个连接的目的。

其实网络通信过程中的系统调用:前面两个函数的阻塞的根因是因为内核的accept和recv的系统调用是阻塞调用,所以会有BIO。

这段程序中涉及到的系统调用如下:

java的bio对应的包是:java.io.*

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

2.非阻塞IO(noblocking I/O)

java的nio对应的:java.nio.*(jdk1.4之后才有)

import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

下面是一段典型的java nio服务端的代码:其中

ss.configureBlocking(false)//很重要,表示设置为非阻塞io

ss.accept在非阻塞模式下不会阻塞,

  • 非阻塞模式:在调用accept方法后,如果无连接建立,则返回null(实际上系统调用的返回时-1,java返回时null);如果有连接,则返回SocketChannel。

我们就达到一个线程监听多个请求的作用。前面的BIO需要多个线程才能同时监听到多个请求。

SocketChannel简述:ServerSocketChannel简述_weixin_33951761的博客-CSDN博客

注意for循环需要遍历所有连接,向内核发送recv系统调用,系统调用会产生软中断造成用户态内核态上下文切换,有很多无效系统调用。那怎么很容易想到减少系统调用的次数。

所以我们有了多路复用器,进程发生系统调用前,先去查下有多少个可以读:

IO多路复用

目前支持I/O多路复用的系统调用有 select,pselect,poll,epoll,I/O多路复用就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。epoll跟select都能提供多路I/O复用的解决方案。在现在的Linux内核里有都能够支持,其中epoll是Linux所特有,而select则应该是POSIX所规定,一般操作系统均有实现。关于io多路复用可参考此文:网络通信 --> IO多路复用之select、poll、epoll详解 - 蚂蚁吃大象、 - 博客园

对于 select 这种⽅式,需要进⾏ 2 次「遍历」⽂件描述符集合,⼀次是在内核态⾥,⼀个次是在⽤户态⾥ ,⽽且还会发⽣ 2 次「拷⻉」⽂件描述符集合,先从⽤户空间传⼊内核空间,由内核修改后,再传出到⽤户空间中。

select 使⽤固定⻓度的 BitsMap,表示⽂件描述符集合,⽽且所⽀持的⽂件描述符的个数是有限制的,在Linux 系统中,由内核中的 FD_SETSIZE 限制, 默认最⼤值为 1024 ,只能监听 0~1023 的⽂件描述符。poll 不再⽤ BitsMap 来存储所关注的⽂件描述符,取⽽代之⽤动态数组,以链表形式来组织,突破了
select 的⽂件描述符个数限制,当然还会受到系统⽂件描述符限制。
但是 poll 和 select 并没有太⼤的本质区别,都是使⽤「线性结构」存储进程关注的 Socket 集合,因此都需要遍历⽂件描述符集合来找到可读或可写的 Socket,时间复杂度为 O(n),⽽且也需要在⽤户态与内核态之间拷⻉⽂件描述符集合,这种⽅式随着并发数上来,性能的损耗会呈指数级增⻓

高版本的jdk主要是用的是epoll系统调用:epoll是在2.6内核中提出的,是之前的select和poll的增强版本。相对于select和poll来说,epoll更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次

基本原理:epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就绪态,并且只会通知一次。还有一个特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。Epoll对于多核来说很友好,相对于前面两个系统调用,多了create和ctl,意味这不用每次都传很多的文件描述符,但是在内核里面增加了两块空间。空间换时间的做法。

java实际上用的是操作系统的系统调用来实现的自己的多路复用,也就是操作系统的多路复用是java的多路复用的基础。

Reactor模型

刚刚的select和epoll都是关注某个io连接产生的事件。但是实际上,我们在处理io的时候往往最关注的有相关业务的处理,并且我们关注的也不是网络io的处理,而是之关心某个事件触发然后执行相应的业务逻辑。所以我们需要封装一层,将事件和IO多路复用抽象出来,我们自己可以选择自己的实现,来方便我们进行IO编程。使得的IO编程更加灵活。

组成:阻塞IO+IO多路复用

特征:以事件循环、事件驱动、事件回调来实现业务逻辑处理

Reactor模式的抽象:

a, Handle表示句柄,文件描述符、socket等; 实际上就是对IO事件的抽象。实际上就是对fd进行了包装。

b, EventDemultiplexer表示多路分发机制,调用系统提供的多IO路复用,比如select,epoll。 程序先将关注的句柄注册到EventDemultiplexer,当有相关事件到来触发EventDemultiplexer通知程序。

c, EventHandler定义事件处理方法,

d, Reactor是事件管理的接口,注册和销毁事件,并运行事件循环,当EventDemultiplexer返回Handle有事件"就绪",将其分发给EventHandler上对应的方法。

e, ConcreteEventhandler实现每个事件的处理逻辑。

Netty是典型的Reactor模型结构,关于Reactor的详尽阐释,本文站在巨人的肩膀上,借助 Doug Lea(就是那位让人无限景仰的大爷)的“Scalable IO in Java”中讲述的Reactor模式。

“Scalable IO in Java”的地址是:http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

​​​​​​​

此文来自于网课记录一下

历程:

计算机IO系列(二)BIO/NIO/多路复用实现相关推荐

  1. 【计算机IO系列零】应用软件部分

    应用程序的IO操作,实际上不是物理设备级别的读写,而是缓存的复制. 1.1. Java IO读写原理 为了避免用户进程直接操作内核,保证内核安全,操作系统将内存(虚拟内存)划分 为两部分,一部分是内核 ...

  2. epoll nio区别_大厂面试系列(二)::NIO和Netty

    NIO和Netty面试题 NIO 阐述 NIO原理? BIO/NIO/AIO有什么区别?有那些实现? 讲讲NIO的原理与实现?NIO用到了哪个经典技术思想?JDK1.8中NIO有做什么优化 了解多路复 ...

  3. Java的IO流 ,BIO NIO AIO 的区别?

    目录 1.在了解不同的IO之前先了解:同步与异步,阻塞与非阻塞的区别: 2.BIO NIO AIO 分别代表什么?(面试简答): 3.BIO和NIO.AIO的区别: 4.java中io流的分类: •  ...

  4. 计算机IO系列「一」零拷贝技术

    深入剖析Linux IO原理和几种零拷贝机制的实现 转载自:深入剖析Linux IO原理和几种零拷贝机制的实现 - 知乎 前言 零拷贝(Zero-copy)技术指在计算机执行操作时,CPU 不需要先将 ...

  5. 计算机IO系列「零」计算机IO【硬件部分】

    背景:最近遇到了io等待导致我整个系统挂掉的问题,当然是因为其它原因.一只对io从硬件到软件.阻塞和非阻塞这些概念一知半解,故记录一下了解到过程 1..总线: IO是通过共享一条总线的方式来实现的,总 ...

  6. Java IO模型:BIO NIO AIO及netty介绍

  7. Java IO BIO NIO

    Java IO BIO NIO 一.Java I/O概述 1.1 什么是流 1.2 流的分类 1.3 字符流 1.3.1 Reader 1.3.2 Writer 1.4 字节流 1.4.1 Input ...

  8. IO回忆录之怎样过目不忘(BIO/NIO/AIO/Netty)2017版

    有热心的网友加我微信,时不时问我一些技术的或者学习技术的问题.有时候我回微信的时候都是半夜了.但是我很乐意解答他们的问题.因为这些年轻人都是很有上进心的,所以在我心里他们就是很优秀的,我愿意多和努力的 ...

  9. 【操作系统三】图解网络IO(bio\nio\slect\epoll)

    [操作系统三]图解网络IO+实战 一.计算机组成 二.系统中断 三.晶振(时间中断.分时复用) 四.事件中断 1.DMA 2.事件中断 3.网卡也会产生中断? 五.linux系统知识 1.linux下 ...

最新文章

  1. 父与子的编程python_父母在人生尚有来处,父母去人生只剩归途!(看一次,哭一次)...
  2. pip如何安装whl
  3. dedecms插件开发教程
  4. loj10165. 「一本通 5.3 例 3」Windy 数
  5. 面试必备:多线程学习(一)
  6. mysql建表注意事项,关键字和保留字不能作为表名
  7. reids实现分布式锁两种方式,单机,集群
  8. 单片机:Keil的安装教程
  9. 第十一届蓝桥杯省赛B组真题训练
  10. 多旋翼飞行器设计与控制(四) —— 动力系统建模与估计
  11. 解决网页内容自制不了,文档复制需要VIP权益方法
  12. 兽药销售终端如何摆脱客情困局
  13. mysql column specified twice_Column 'box_id' specified twice 错误
  14. ② 判断语句、循环语句
  15. xshell如何导入.xsh 文件
  16. Python fractions模块 —— 分数相关函数
  17. console用法java_Java Console printf(String, Object)用法及代码示例
  18. 微积分在金融投资的应用
  19. 欧姆龙PLC远程上下载实际操作分享
  20. jupyter中interrupt the kernel(中断)没有反应

热门文章

  1. 一个打印螺旋数的程序
  2. Microsoft Speech SDK 5.1
  3. mysql开启perform sch_MySQL Performance schema设置的一些建议选项
  4. t检验自由度的意义_T检验、F检验和统计学意义
  5. python程序流程控制_python流程控制
  6. java 图像倾斜角度计算_【干货】无人机航测倾斜实景三维建模进行土方计算(基于Smart3D全面讲解)...
  7. linux上安装hackrf_在Linux上安装Kubectl
  8. dev chartcontrol获取x y轴的值_终于,奔驰强势接手了腾势X
  9. 九十六、双指针和滑动窗口算法模板
  10. 十一、练习:爬取图虫网付费图片