一、了解Unix网络编程5种I/O模型
1.1、阻塞式I/O模型
阻塞I/O(blocking I/O)模型,进程调用recvfrom,其系统调用直到数据报到达且被拷贝到应用进程的缓冲区中或者发生错误才返回。进程从调用recvfrom开始到它返回的整段时间内是被阻塞的。
1.2、非阻塞式I/O模型
当一个应用进程像这样对一个非阻塞描述字循环调用recvfrom时,我们称之为轮询(polling)。应用进程持续轮询内核,以查看某个操作是否就绪。
1.3、I/O多路复用(事件驱动)模型
1.4、信号驱动式I/O(SIGIO)
1.5、异步I/O模型
1.6、I/O模型的比较:
根据上述5种IO模型,前4种模型-阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步I/O模型,因为其中真正的I/O操作(recvfrom)将阻塞进程,在内核数据copy到用户空间时都是阻塞的。
1.7、同步IO、异步IO、阻塞IO、非阻塞IO
一个IO操作可以分为两个步骤:发起IO请求和实际的IO操作
例如:
1、操作系统的一次写操作分为两步:将数据从用户空间拷贝到系统空间;从系统空间往网卡写。
2、一次读操作分为两步:将数据从网卡拷贝到系统空间;将数据从系统空间拷贝到用户空间。
阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。
同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统做完IO两个阶段的操作再将结果返回,那么就是异步IO。
1.8、IO多路复用
IO多路复用,就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
从流程上来看,使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还多了添加监视socket,以及调用select函数的额外操作,效率更差。但是,使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。
IO多路复用方式允许单线程内处理多个IO请求,但是每个IO请求的过程还是阻塞的(在select函数上阻塞),平均时间甚至比同步阻塞IO模型还要长。如果用户线程只注册自己感兴趣的socket或者IO请求,然后去做自己的事情,等到数据到来时再进行处理,则可以提高CPU的利用率。
由于select函数是阻塞的,因此多路IO复用模型也被称为异步阻塞IO模型。注意,这里的所说的阻塞是指select函数执行时线程被阻塞,而不是指socket。一般在使用IO多路复用模型时,socket都是设置为NONBLOCK的,不过这并不会产生影响,因为用户发起IO请求时,数据已经到达了,用户线程一定不会被阻塞。
IO多路复用是最常使用的IO模型,但是其异步程度还不够“彻底”,因为它使用了会阻塞线程的select系统调用。因此IO多路复用只能称为异步阻塞IO,而非真正的异步IO。
展示了非阻塞IO如何让你使用一个selector区处理多个连接.
1.9、select、poll、epoll
Linux支持IO多路复用的系统调用有select、poll、epoll,这些调用都是内核级别的。但select、poll、epoll本质上都是同步I/O,先是block住等待就绪的socket,再是block住将数据从内核拷贝到用户内存。
1.10、两种I/O多路复用模式:Reactor和Proactor
在这两种模式下的事件多路分离器反馈给程序的信息是不一样的:
1.Reactor模式下说明你可以进行读写(收发)操作了。
2.Proactor模式下说明已经完成读写(收发)操作了,具体内容在给定缓冲区中,可以对这些内容进行其他操作了。
Reactor关注的是I/O操作的就绪事件,而Proactor关注的是I/O操作的完成事件
一般地,I/O多路复用机制都依赖于一个事件多路分离器(Event Demultiplexer)。分离器对象可将来自事件源的I/O事件分离出来,并分发到对应的read/write事件处理器(Event Handler)。
Reactor模式采用同步IO,而Proactor采用异步IO。
在Reactor中,事件分离器负责等待文件描述符或socket为读写操作准备就绪,然后将就绪事件传递给对应的处理器,最后由处理器负责完成实际的读写工作。
而在Proactor模式中,处理器或者兼任处理器的事件分离器,只负责发起异步读写操作。IO操作本身由操作系统来完成。传递给操作系统的参数需要包括用户定义的数据缓冲区地址和数据大小,操作系统才能从中得到写出操作所需数据,或写入从socket读到的数据。事件分离器捕获IO操作完成事件,然后将事件传递给对应处理器。比如,在windows上,处理器发起一个异步IO操作,再由事件分离器等待IOCompletion事件。典型的异步模式实现,都建立在操作系统支持异步API的基础之上,我们将这种实现称为“系统级”异步或“真”异步,因为应用程序完全依赖操作系统执行真正的IO工作。
Reactor和Proactor模式的主要区别就是真正的读取和写入操作是有谁来完成的,Reactor中需要应用程序自己读取或者写入数据,而Proactor模式中,应用程序不需要进行实际的读写过程,它只需要从缓存区读取或者写入即可,操作系统会读取缓存区或者写入缓存区到真正的IO设备.
二、Java NIO
NIO,有人称之为New I/O,因为它相对于之前的I/O类库是新增的,所以被称为New I/O。但是,由于之前老的 I/O 类库是阻塞 I/O,New I/O类库的目标就是要让Java支持非阻塞 I/O,所以,更多的人喜欢称之为非阻塞 I/ O(Non-block I/O)。
2.1、对NIO的非阻塞的理解
注意,select是阻塞的,无论是通过操作系统的通知(epoll)还是不停的轮询(select,poll),这个函数是阻塞的。所以你可以放心大胆地在一个while(true)里面调用这个函数而不用担心CPU空转。
NIO采用Reactor模式,一个Reactor线程聚合一个多路复用器Selector,它可以同时注册、监听和轮询成百上千个Channel,一个IO线程可以同时并发处理N个客户端连接,线程模型优化为1:N(N < 进程可用的最大句柄数)或者M : N (M通常为CPU核数 + 1, N < 进程可用的最大句柄数)。
JAVA NIO 不是同步非阻塞I/O吗,为什么说JAVA NIO提供了基于Selector的异步网络I/O?
java nio的io模型是同步非阻塞,这里的同步异步指的是真正io操作(数据内核态用户态的拷贝)是否需要进程参与。
而说java nio提供了异步处理,这个异步应该是指编程模型上的异步。基于reactor模式的事件驱动,事件处理器的注册和处理器的执行是异步的。
AIO(Async I/O)里面会更进一步:不但等待就绪是非阻塞的,就连数据从网卡到内存的过程也是异步的。
换句话说,BIO里用户最关心“我要读”,NIO里用户最关心"我可以读了",在AIO模型里用户更需要关注的是“读完了”。
NIO一个重要的特点是:socket主要的读、写、注册和接收函数,在等待就绪阶段都是非阻塞的,真正的I/O操作是同步的(消耗CPU但性能非常高)。
2.2、如何结合事件模型使用NIO非阻塞特性
BIO模型,之所以需要多线程,是因为在进行I/O操作的时候,一是没有办法知道到底能不能写、能不能读,只能"傻等",即使通过各种估算,算出来操作系统没有能力进行读写,也没法在socket.read()和socket.write()函数中返回,这两个函数无法进行有效的中断。所以除了多开线程另起炉灶,没有好的办法利用CPU。
NIO的读写函数可以立刻返回,这就给了我们不开线程利用CPU的最好机会:如果一个连接不能读写(socket.read()返回0或者socket.write()返回0),我们可以把这件事记下来,记录的方式通常是在Selector上注册标记位,然后切换到其它就绪的连接(channel)继续进行读写。
我们大概可以总结出NIO是怎么解决掉线程的瓶颈并处理海量连接的:
NIO由原来的阻塞读写(占用线程)变成了单线程轮询事件,找到可以进行读写的网络描述符进行读写。除了事件的轮询是阻塞的(没有可干的事情必须要阻塞),剩余的I/O操作都是纯CPU操作,没有必要开启多线程。
并且由于线程的节约,连接数大的时候因为线程切换带来的问题也随之解决,进而为处理海量连接提供了可能。
2.3、理解异步非阻塞I/O
很多人喜欢将JDK1.4提供的NIO框架称为异步非阻塞I/O,但是,如果严格按照UNIX网络编程模型和JDK的实现进行区分,实际上它只能被称为非阻塞I/O,不能叫异步非阻塞I/O。在早期的JDK1.4和1.5 update10版本之前,JDK的Selector基于select/poll模型实现,它是基于I/O复用技术的非阻塞I/O,不是异步I/O。在JDK1.5 update10和Linux core2.6以上版本,Sun优化了Selctor的实现,它在底层使用epoll替换了select/poll,上层的API并没有变化,可以认为是JDK NIO的一次性能优化,但是它仍旧没有改变I/O的模型。
由JDK1.7提供的NIO2.0,新增了异步的套接字通道,它是真正的异步I/O,在异步I/O操作的时候可以传递信号变量,当操作完成之后会回调相关的方法,异步I/O也被称为AIO。
NIO类库支持非阻塞读和写操作,相比于之前的同步阻塞读和写,它是异步的,因此很多人习惯于称NIO为异步非阻塞I/O,包括很多介绍NIO编程的书籍也沿用了这个说法。为了符合大家的习惯,我们也将NIO称为异步非阻塞I/O或者非阻塞I/O。
三、Java NIO的核心组成
3.1、通道(Channel) 和 缓冲区(Buffer)
基本上,所有的 IO 在NIO 中都从一个Channel 开始。Channel 有点象流。 数据可以从Channel读到Buffer中,也可以从Buffer 写到Channel中。这里有个图示:
3.2、多路复用器(Selector)
Selector允许单线程处理多个Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。
这是在一个单线程中使用一个Selector处理3个Channel的图示:
要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。
四、总结
最后总结一下到底NIO给我们带来了些什么:
事件驱动模型
避免多线程
单线程处理多任务
非阻塞I/O,I/O读写不再阻塞,而是返回0
基于block的传输,通常比基于流的传输更高效
更高级的IO函数,zero-copy
IO多路复用大大提高了Java网络应用的可伸缩性和实用性
相关推荐
[第4节] JavaNIO流-通道1.flv [第5节] Java NIO流-通道2.flv [第6节] Java NIO流-socket通道操作.flv [第7节] Java NIO流-文件通道操作.flv [第8节] Java NIO流-选择器 .flv [第9节] Java NIO流-选择器操作.flv...
涉及到java io, nio, aio相关知识点,学习过程中的一些总结,持续更新中,xmind 格式
java NIO,AIO编程.txt 网盘永久链接 为方便java nio aio 学习爱好者而上传
Java作为一门广泛使用的开发语言,提供了多种I/O(Input/Output)通信模型,包括传统的阻塞I/O(BIO)、非阻塞I/O(NIO)以及异步I/O(AIO)。这些通信模型在不同的场景下有着各自的优势,理解和掌握它们对于优化...
Java BIO NIO AIO Java BIO、NIO、AIO是 Java 中的三种 I/O 模式,每种模式都有其特点和应用场景。下面对每种模式进行详细解释。 Java BIO Java BIO( Blocking I/O)是一种同步阻塞式的 I/O 模式,即服务器实现...
为了处理与外部世界的交互,Java提供了三种不同的I/O模型:BIO( Blocking I/O)、NIO(Non-blocking I/O)和AIO(Asynchronous I/O)。这些模型各有优缺点,适用于不同场景。下面我们将深入探讨这三种I/O模型,并...
全面理解 Java 网络编程 - BIO、NIO、AIO 本课程旨在帮助学生全面理解 Java 网络编程中的 BIO、NIO、AIO 三剑客,掌握 RPC 编程的基础知识,并结合实战项目巩固所学。 一、网络编程三剑客 - BIO、NIO、AIO BIO...
【Java 高并发八:NIO和AIO详解】 NIO(New Input/Output),从Java 1.4版本开始引入,是对传统IO模型的一种改进。传统的IO模型基于流(Stream),而NIO则基于块(Block)进行数据传输,提高了处理大量数据时的效率...
对java io总结时编写的测试代码,包括BIO,NIO,AIO的实现,Java io操作是编程人员经常使用到的,以前只是使用没有对这三种IO做系统的了解,本文将对这三种IO作详细的介绍并附有测试完整代码
该项目是一款基于Java NIO/AIO技术的鹊桥内网穿透设计源码,包含360个文件,涵盖171个JavaScript文件、101个Java源文件、23个HTML文件、17个XML文件、13个CSS文件、7个PNG图片文件、6个Shell脚本文件、5个属性文件、...
鹊桥,又称为MagpieBridge,是一款基于Java的内网穿透工具,利用先进的异步I/O模型(AIO/NIO)来实现高效的网络通信。它为开发者提供了在内网环境中进行开发并允许外部进行调试的强大功能,对于远程协作、云服务测试...
Java IO、NIO、AIO 详解 Java IO、NIO、AIO 是 Java 语言中三种不同的输入/输出机制,分别对应着不同的编程模型和设计理念。在高并发环境中,选择合适的输入/输出机制非常重要,本文将对 Java IO、NIO、AIO 进行...
Java NIO(非阻塞I/O)和AIO(异步I/O)是Java平台中用于提高I/O性能的重要技术。在传统的Java BIO(阻塞I/O)模型中,一个线程对应一个连接,当服务器处理大量并发连接时,线程资源消耗大,效率较低。而NIO和AIO则...
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统I/O模型的新技术。尚硅谷的12讲Java NIO课程,旨在深入浅出地讲解这一重要概念,帮助开发者提升程序的性能和效率。...
NIO,AIO编程
AIO(异步I/O)又称NIO.2,是在Java 7中引入的。AIO的主要特点是,用户线程发起I/O操作后,无需等待,可以继续执行其他任务,等到I/O操作完成时,系统会通过回调或者事件通知用户线程。这种方式使得应用可以更加高效...
《Java IO:从NIO到Reactor三种模式详解》 在Java编程中,IO操作是不可或缺的一部分,尤其在处理大量数据传输或者网络通信时。本文将深入探讨Java中的三种IO模型:传统IO(BIO)、非阻塞IO(NIO)以及反应器模式...
### 2024年Java常见BIO、NIO、AIO、Netty面试题解析 #### 一、基础知识概述 1. **IO概念**: - Java中的I/O(Input/Output)指的是输入输出操作,它以流为基础进行数据的输入输出。所有的数据在Java中都是以流的...