IO NIO 面向流 面向缓冲 阻塞IO 非阻塞IO 无 选择器
2 网络协议:系统间的信息传递依赖于网络。这块侧重于OSI模型参考的7层或者5层协议。
3 通信方式(框架):这才是我们常见的网络I/O模型。
那去银行排队举例子(或者去餐馆吃饭)
阻塞I/O和非阻塞I/O :程序级别,主要描述程序请求操作系统I/o操作后,等待消息通知时,程序如何处理。
阻塞I/O等待,非阻塞I/O继续执行(使用线程一直轮询,直到网络I/O准备好了)
举例:1阻塞:排队过程啥也不干。
2.非阻塞:一边排队,一边玩手机。有线程切换的过程。
同步I/O 和异步I/O: 操作系统级别(与消息的通知机制有关),主要描述的是操作系统在收到程序请求操作网路I/O之后,如何响应: 同步I/O 不响应,直到网络I/O资源准备好。异步I/O返回一个标记,当网络I/O资源准备好之后,再用事件机制返回给程序。
举例:1同步:排队等通知。
2.异步:择取一个小纸条上面有我的号码,柜台叫号。
二 阻塞模式
2.1 同步阻塞
网络编程的基本模型是C/S模型,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。
该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,多线程不能从本质上解决:操作系统通知accept是单个线程运行的,线程是系统宝贵资源(创建及切换)。相关代码就是socket编程。
举例:餐厅一个服务员,一份菜单,一个人点完了下一个点。效率最低。
2.2 改进 使用线程池
实现1个或多个线程处理N个客户端的模型(但是底层还是使用的同步阻塞I/O),通常被称为“伪异步I/O模型“,不是我们俗称的NIO。
2.3 同步非租塞
比如设置了超时时间,再去轮询。
举例:N个服务员,N份菜单,每来一个顾客就有服务员提供菜单点菜,资源消耗大。
三 NIO
NIO基于Reactor,当socket有流可读或可写入socket时,操作系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操作系统。底层依赖操作系统的select,poll,epool,kqueue技术。
Java对于NIO支持的模型如下,涉及的概念buffer,channel,selector。
Buffer是一个对象,包含一些要写入或者读出的数据。 在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,也是写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
缓冲区实际上是一个数组,并提供了对数据结构化访问以及维护读写位置等信息。具体的缓存区有这些:ByteBuffe、CharBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。他们实现了相同的接口:Buffer。
我们对数据的读取和写入要通过Channel,它就像水管一样,是一个通道。通道不同于流的地方就是通道是双向的,可以用于读、写和同时读写操作。 底层的操作系统的通道一般都是全双工的,所以全双工的Channel比流能更好的映射底层操作系统的API。Channel主要分两大类: SelectableChannel:用户网络读写 FileChannel:用于文件操作
Selector是Java NIO 编程的基础。Selector提供选择已经就绪的任务的能力:Selector会不断轮询注册在其上的Channel,如果某个Channel上面发生读或者写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作。
这里需要补充一下:NIO技术是依赖于操作系统内核实现的,JVM为跨平台实现创建了一个统一的抽象组,并且为不同操作系统进行具体实现,具体是java.nio.channels.spi包下面的SelectorProvider抽象类。这里主要方法有:
openDatagramChannel 创建和操作系统匹配的UDP通道实现。
openSelector 创建和操作系统匹配的选择器。
openServerSocketChannel 创建和操作系统匹配的服务器端通道。
openSocketChannel 创建和NIO 模型匹配的TCP socket套接字通道,用来反映客户端的TCP连接。
除此之外,nio还有java.nio.charset,这个跟字符的编解码有关。java.nio.file 有多种操作文件系统中文件方法,跟path结合使用。
这块的东西还是很多的,需要深入学习。
NIO优点:绕过了I/O在操作系统accept的阻塞问题,可以使操作系统在一个端口能同时受理多个客户端的I/O操作(端口数据接受规则只和选择器注册的关心事件有关)。
但是属于同步I/O模型,同步就是说:上层应用系统询问底层某个事件发生,底层不会主动告诉上层。
举例: 一个服务员,N份菜单,顾客拿菜单选好菜叫服务员,服务员可以记录多分点菜交给厨师。
异步I/O采用订阅-通知模式,即程序向操作系统注册I/O监听,然后继续做自己的事。操作系统在I/O准备好后,主动推送程序,触发响应函数。异步的套接字通道时真正的异步非阻塞I/O,对应于UNIX网络编程中的事件驱动I/O(AIO)。他不需要过多的Selector对注册的通道进行轮询即可实现异步读写。
Java从jdk7开始,提供AIO支持。这部分内容被称作NIO.2,主要在java.nio.channels包下增加了下面四个异步通道:
其中的read/write方法,会返回一个带回调函数的对象,当执行完读取/写入操作后,直接调用回调函数。
同步和异步(操作系统级别)仅仅是关注的消息如何通知的机制,而阻塞与非阻塞(程序级别)关注的是程序请求操作系统I/o操作后,等待消息通知时,程序如何处理的状态。
这里实际应用更多的是NIO框架,就是netty了。
参考:https://blog.csdn.net/anxpp/article/details/51512200