NIO重要组件
本篇不打算含有过多的代码解释,大概率是纯原理的文章,旨在更加理解Netty框架的底层原理 – NIO的原理。接下来认识一下最重要的三个组件。
Channel
顾名思义这是通信管道的意思,在NIO中充当数据通道的作用。
NIO所有数据都通过Buffer
对象处理;不会将字节写入channel
通道中,但是将字节数据可以写入缓冲区;同理,你也不能在channel
通道中读取到字节,而是将数据输入到缓冲区,然后channel
从缓冲区读取字节。
channel
通道是双向的,不像是BIO那样是流(单向的),所以可以同时读写数据。
Buffer
在数据打包和传输的方式上,BIO是面向流进行传输的,也就是一个字节一个字节这样传输,效率是比较慢的;而NIO就是面向块进行传输的。
缓冲区一般来说是个字节数组,但又不仅仅是个字节数组,还是一个可以跟踪系统的读/写进程。
缓冲区类型用的最多的是ByteBuffer
,八大数据类型每个都有自己的缓冲区类型。
缓冲区中有三个重要的状态变量:position
、limit
、capacity
。
position
:表明下次读/写数据的位置;limit
:写模式下还可以写入多少数据、读模式下还可以读取多少数据;capacity
:表明缓冲区的最大存储数据容量;
开始 初始化capacity
为7的字节数组,此时position
为0,limit
为6;
开始写入数据,比如写入3个数据,此时position
就到了该位置。
切换到读取数据模式,调用flib()
方法
- 将
limit
设置到position
的位置; - 将
position
设置为0;
之后就一直读取数据,知道position
== limit
,要知道 position
是要小于或者等于 limit
的。调用clear()
方法。
clear()
方法主要做了两件事:
- 将
limit
设置为capacity
相同; - 设置
position
为0。
Selector
传统的BIO中,写出和读取数据都是会阻塞的,需要等到完全读取或者完全写出才能有下一步的操作。所以需要采用异步IO,在读取数据的同时也可以写出数据。同步程序常常要 求助于 轮询,或者创建大量的线程连接;而异步程序不需要求助轮询,只需要少数的线程就可以监听管理任何通道的事件。
下面内容是参考 知乎 岛雨 的文章;
我们知道BIO中,有两个阻塞(监听阻塞、读取/写出数据时阻塞),而NIO就是为了解决这两个根本的阻塞而产生的;
代码就不实现了。。。。。
讲selector
之前首先我们要了解IO多路复用器
根据操作系统的知识我们知道,计算机硬件资源是有内核态来控制的,而我们的程序是运行在用户态的,但IO相关的函数是在内核态的。所以发生IO读写操作的时候,会有内核态到用户态的切换过程,而这个过程代价很大,需要减少切换次数。
在没有selector
时我们在内核态和用户态的切换过程中付出的代价很大,由此,看能不能一次性将把要检查的socket
全部扔给内核态,让内核态告诉我们有哪些socket有客户端来连接了,有哪些socket有客户端来发送数据了,然后针对性地做出相应的处理即可,而不是一个一个socket
连接去找内核检查对应的状态。IO多路复用器应运而生。
Selector类 = NIO + IO多路复用器 封装
简单来说Selector就是一条线程可以管理多个管道