Netty的前期准备:初探NIO中的缓冲区

NIO的参考文档

1 http://blog.sina.com.cn/s/blog_81c2545a01011afh.html

只要是网络操作,就涉及到IO读写,那自然离不开数据缓存。

NIO作为Netty的异步IO提供商,内部的缓冲区是各种各样的Buffer子类。

所以掌握Buffer是非常有必要的。

正所谓“工欲善其事,必先利其器”嘛。

---------------------------------------------------------------------------

常用的就是ByteBuffer,所以下面以此为例子,(喜欢字节,封装神马的最让人痛恨!!!)

分配

ByteBuffer buffer = ByteBuffer.allocate(100);  分配一个100字节容量的缓冲区
 byte[] data=buffer.array(); 直接获取其内部存储对象,可直接修改,

请注意这里的修改是真实的修改缓冲区对应的存储对象。

所以不需要再次对缓冲区buffer进行操作就可以保留修改。

直接分配

《JAVA网络编程》P353 ---除非性能是个问题,否则不应考虑使用此类型的直接缓冲区

包装

实际上就是构造时初始化一些内容。有点类似于malloc和calloc的区别。

包装与分配的区别在于:

分配是重新构造一个新的数组,然后传给某个构造函数。

包装是直接引用之前内容所在的数组,然后传给某个构造函数。

本质都是一样的。

---

填充的例子:

171426_bdVi_1382024.png

可见pos慢慢增加,pos其实就是下一个可写入的位置,当没有填入任何东西时,pos自然是0.

----------------------------------------------------------------------------------------------------

缓冲区最多只能填充到最大容量,否则会报错,比如:

172909_LqSJ_1382024.png

其实报错的逻辑是这样的:

public ByteBuffer put(byte x) {

 

hb[ix(nextPutIndex())] = x;

return this;

 

    }

但是在计算nextPutIndex会做校验,校验的代码是这样的:

final int nextPutIndex() { // package-private

if (position >= limit)

    throw new BufferOverflowException();

return position++;

    }

不难理解了吧。

------------------------------------------------------------------------------------

其实根据打印的信息,此时的那些position limit capacity,

基本表示的意思就是:下一个可写入的字符位置 ,最大可写入字符位置(哨兵角色),总容量个数。

这个从上面的nextPutIndex通过position和limit比较也验证了这一点。

------------------------------------------------------------------------------------

此时,如果写入结束的话,想读取,就必须执行一个flip函数。

174114_WFie_1382024.png

为啥变成了pos=0,lim=5,cap=12呢。

其实也就是说:你不是想读取么,好啊,下一个可读取的位置是0,最多可以读到5,总的缓存区容量还是12个。

这个是为读做了一个准备!下面就真的可以开始读取了!

174632_nof3_1382024.png

我们看看hasRemaining()的代码,我猜是把pos跟lim比较,

 

public final boolean hasRemaining() {

return position < limit;

    }

代码果然如此。

再看看get,是把position当前位置的内容返回,然后把position自增一个。

毫无秘密可言,真是蛋疼,我还是喜欢C的简单直白。

简单粗暴,不那么多废话。

===========================================

除了利用ByteBuffer提供的各种啰嗦API之外,如果你喜欢简单粗暴的方法的话。

ByteBuffer也满足你。(控制狂专用API)

buffer.put(index,'H');

buffer.get(index);

因为你直接指定了index.

看一看代码实现:

 

public byte get() {

return hb[ix(nextGetIndex())];

    }

 

    public byte get(int i) {

return hb[ix(checkIndex(i))];

    }

 

就不用我多说啥了。

究极控制狂的方法:

byte[] data = buffer.array();

好吧,你厉害,你拿到了缓冲区的数组,连指示器都不要了,

你就把它当做一个数组来用吧。

话说,如果这样做的话,还要ByteBuffer干嘛。:)

因为如果你直接操作一个数组的话,你还是需要若干指示器。

--------------------------------------------

ByteBuffer同样提供了批量操作方法,原理都是一样,

这里我就不给API了,自己去看代码吧。

--------------------------------------------

视图缓冲区

哎,还能不能给人自我控制的感觉了,封装这么多干嘛。。。

 

压缩缓冲区

也就是说,你之前正在写,写了一半,然后还剩下若干字节

这若干字节左边是空的,右边是空的。

这不是很尴尬嘛,要是把中间这几个字节挪到最左边从0开始就好了。

compact就是干这个的,汗。

 

183408_IdlY_1382024.png

很简单,没啥好说的了。

JAVA就是折腾。。。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/qiangzigege/blog/389809