netty极简教程(二): nio Buffer的原理及使用

我们知道,netty直接与jdk的原生nio开发的,可以说是jdk nio的增强,所以理解jdk nio的机制就变得非常重要,接下来将介绍jdk中关于nio的几个非常重要的组件, 示例源码: https://github.com/jsbintask22/netty-learning

ByteBuffer介绍

对比jdk bio的写法,在从Socket读取数据的时候,不管是客户端还是服务端,我们通常需要将字节读取到一个字节数组,知道读取的数据长度满足所需要的条件:


socket通信模型
InputStream is = socket.getInputStream();
byte[] buff = new byte[1024];
int len;

while ((len = is.read(buff)) != -1) {
    System.out.println("client msg: " + new String(buff, 0, len));
}

这里的buff我们就可以认为是一个数据容器,后续的其他处理(比如这里的 new String)都会从这个数据容器中取。


而在nio编程中,这个字节数组改为了一个可重复使用的容器Buffer(java.nio.Buffer),它有多种同类型的基本类型子类,它的结构如下:

image

假设有一个长度为n的容器。

  1. position指针代表洗一个可以读或者可以写入的位置索引,初始状态则指向0
  2. limit代表下一个不能写入或者读取的位置,初始位置则指向n(注意索引是从0开始的)
  3. capacity总是表示容器的大小,总是为n
  4. mark作为一个标志为,当调用mark()方法时,会将position赋值给mark, 这样在下次调用reset()方法的时候可以让position回到上次标志的位置
    有了以上这些,在写入或者读取时总是会移动position的位置,而如果想重置复原则需要移动. 它们直接总是会满足这样的关系: mark <= position <= limit <= capacity

这里指的注意的是 position 代表的是下一个可以读或者可以写的位置,所以读写均会移动位置。

Buffer使用

以IntBuffer为例,介绍下它的使用,IntBuffer继承自Buffer,内部使用一个整型数组存储数据 final int[] hb;


  1. 向容器中存储数据: put(int i);, put(int index, int i); 从指定位置的存储不会移动 position 指针的位置。
  2. 获取数据: int get();, int get(int index); 从指定索引位置获取数据不会移动 positon 位置.
  3. 检查是否有有效数据: 检查position 是否小于limit即可 .return position < limit;
IntBuffer intBuffer = IntBuffer.allocate(10); // 1
for (int i = 0; i < intBuffer.capacity(); i++) {
    intBuffer.put((i + 1));  // 2
}

intBuffer.flip();  // 3
while (intBuffer.hasRemaining()) {  // 4
    int i = intBuffer.get();  // 5
    System.out.println(i);
}

intBuffer.rewind();
while (intBuffer.hasRemaining()) {
    int i = intBuffer.get();
    System.out.println(i);
}
  1. 分配一个字节数据,默认在heap上(内部一个长度为10的整型数据)
  2. 写入数据,会移动 position 的位置
  3. 翻转数据区域,将已经写入了数据的区域用limit和position标识出来,即: limit = position; position = 0; remark = -1;
  4. 检查是否有有效数据.
  5. 获取当前position指针的数据,并且向前移动

最后介绍下 rewind, flip, clear三个方法的区别

  1. clear为将所有指针重置为初始状态:position = 0; limit = capacity; mark = -1;,一般用于在进行一系列读写操作后需要重用该容器进行重置.
  2. flip为将有效数据隔离,比如put数据后,调用该方法将数据读取出来 limit = position; position = 0; remark = -1;
  3. rewind用于读取了数据后需要重复读取数据,即将position指针重置为0即可, position = 0; mark = -1;

总结

  1. 在bio编程中,我们通常使用字节数据向socket写入数据或者读取数据到字节数据,而在nio中则一般使用Buffer进行该操作,它有多个基本类型子类,最常用的即是ByteBuffer
  2. Buffer的读写原理为移动其中的position,limit指针
  3. rewind,flip, clear三者区别

扩展: 对于Buffer而言,直接使用子类的allocate方法分配数组在heap上,它还可以分配在堆外内存,称为直接内存,可以实现零拷贝,提高效率

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266