版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qinshi965273101/article/details/81676145
1、NIO简介
NIO面向通道和缓冲区进行工作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。可以双向传输数据,是同步非阻塞式IO。NIO还引入了选择器机制,从而实现了一个选择器监听多个底层通道,减少了线程并发数。用NIO实现socket的Tcp通信需要掌握下面三个知识点:
- Buffer 缓冲区
- Channel 通道
- Selector 选择器
2、java.nio.Buffer
所谓的缓冲区其实就是在内存中开辟的一段连续空间,用来临时存放数据。
java.nio.Buffer
|--ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer
在缓冲区中存在三个基础的游标,capacity(容量),limit(限制位), position(当前位)。
三个游标的大小关系为:position<=limit<=capacity
下面以ByteBuffer为例,理解三个基础游标及Buffer的使用方法:
- ByteBuffer创建后三个游标的位置
//初始化大小为4
ByteBuffer bb = ByteBuffer.allocate(4);
- 向ByteBuffer中写入一个字节数据后三个游标的位置
//向ByteBuffer中放入"a"
bb.put("a".getBytes());
向ByteBuffer中写入一个字节,position则往后移动一个位置,显然,当position移动到位置 4 时,则不能再写入数据。
- 调整position和limit的位置准备读取数据
//读取数据前调整position和limit的位置
bb.flip();
读取数据,其实是读取 position到limit之间的数据。所以读取数据前,需要把position和limit的位置调整如下图:
- 读取数据
byte[] data = new byte[1];
//while(position <= limit)
while(bb.hasRemaining()) {
bb.get(data);
System.out.println(new String(data));
}
读取完数据后,position=limit 。
- 常用方法说明
下列表格摘自博客 https://blog.csdn.net/z69183787/article/details/77102198
allocate(int capacity) | 从堆空间中分配一个容量大小为capacity的byte数组作为缓冲区的byte数据存储器 |
wrap(byte[] array) | 这个缓冲区的数据会存放在byte数组中,bytes数组或buff缓冲区任何一方中数据的改动都会影响另一方。其实ByteBuffer底层本来就有一个bytes数组负责来保存buffer缓冲区中的数据,通过allocate方法系统会帮你构造一个byte数组 |
limit(), limit(10)等 | 其中读取和设置这4个属性的方法的命名和jQuery中的val(),val(10)类似,一个负责get,一个负责set |
mark(),reset() | 调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置 |
clear() | position = 0;limit = capacity;mark = -1; 有点初始化的味道,但是并不影响底层byte数组的内容 |
flip() | limit = position;position = 0;mark = -1; 翻转,也就是让flip之后的position到limit这块区域变成之前的0到position这块,翻转就是将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态 |
rewind() | 把position设为0,mark设为-1,不改变limit的值 |
remaining() | return limit - position;返回limit和position之间相对位置差 |
hasRemaining() | return position < limit返回是否还有未读内容 |
compact() | 把从position到limit中的内容移到0到limit-position的区域内,position和limit的取值也分别变成limit-position、capacity。如果先将positon设置到limit,再compact,那么相当于clear() |
get() | 相对读,从position位置读取一个byte,并将position+1,为下次读写作准备 |
get(int index) | 绝对读,读取byteBuffer底层的bytes中下标为index的byte,不改变position |
get(byte[] dst, int offset, int length) | 从position位置开始相对读,读length个byte,并写入dst下标从offset到offset+length的区域 |
put(byte b) | 相对写,向position的位置写入一个byte,并将postion+1,为下次读写作准备 |
put(int index, byte b) | 绝对写,向byteBuffer底层的bytes中下标为index的位置插入byte b,不改变position |
put(ByteBuffer src) | 用相对写,把src中可读的部分(也就是position到limit)写入此byteBuffer |
put(byte[] src, int offset, int length) | 从src数组中的offset到offset+length区域读取数据并使用相对写写入此byteBuffer |