NIO之ByteBuffer

        NIO中的ByteBuffer是缓冲区,其中有几个比较重要的属性capacity,position和limit。

capacity:

        其中,capacity是缓冲区的容量大小,在分配内存空间后不会改变。

limit:

        limit是限制位置,在读写模式切换后limit的位置也跟着切换,切换到读限制位置和写限制位置。在写模式下limit一般位于capacity处,即不超出buffer的范围即可。在读模式下limit一般位于buffer中最后一个字符的位置,即在读的时候不超出存有内容的范围即可。

position:

        position是写入位置或读取位置,在读写切换时也会随之切换。如写模式下随着字符的写入,position的位置会相应地后移,当切换为读模式时,position会一直最前方,此时其代表读取位置。读取操作结束后在切回写模式时,分为两种情况。第一种是使用clear进行切换,之前缓冲区里的全部元素,无论切换前是否读过,都直接抛弃,position移至buffer的最前方。另一种是compact,这种方式是保留没读过的元素,也就是读模式的position和读模式的limit之间的元素,切换写模式时会被保留,position会指向被保留元素的下一个。

如下列的一些图

一开始:

写入4字节:

flip切换为读模式,position切换到读取位置(最前方),limit切换为读取限制,有元素的最后一个位置:

 读了4个字节后:

以clear切换为写模式,元素清空,limit和position也进行切换:

        假设只读了两个字节,剩下的两个没读,并且是以compact方式进行的切换,那会保留没读过的元素,position和limit也切换为写模式,并且position位于保留元素的后方:

       关于position还有需要注意的是, 我们在读模式下进行读取时,一般是调用buffer的get方法,这时每读一个字符指针就会后移一位。注意可以调用 rewind 方法将 position 重新置为 0,或者调用 get(int i) 方法获取索引 i 的内容,它不会移动读指针。另外,使用mark 可以在读取时做一个标记,即使 position 改变,只要调用 reset 就能回到 mark 的位置,但是需注意rewind 和 flip 都会清除 mark 位置。

       实战举例,解决网络收发数据时的半包粘包情况,灵活利用了ByteBuffer读写模式的切换以及对于position的灵活应用:

public static void main(String[] args) {
    ByteBuffer source = ByteBuffer.allocate(32);
    //                     11            24
    source.put("Hello,world\nI'm zhangsan\nHo".getBytes());
    split(source);

    source.put("w are you?\nhaha!\n".getBytes());
    split(source);
}

private static void split(ByteBuffer source) {
    // 切换为读模式
    source.flip();
    // buffer中容量的总大小
    int oldLimit = source.limit();
    for (int i = 0; i < oldLimit; i++) {
        // 使用source.get(i)的模式,读取位置position并不会后移
        if (source.get(i) == '\n') {
            System.out.println(i);
            // 当前位置与position间的长度是新字符串长度,position是上一个串的结尾
            ByteBuffer target = ByteBuffer.allocate(i + 1 - source.position());
            // 0 ~ limit
            source.limit(i + 1);
            // 从source 读,向 target 写,position后移到该完整串的结尾
            target.put(source); 
            debugAll(target);
            source.limit(oldLimit);
        }
    }
    // 有剩余的半包并未真正读取,切换写模式时保留,等后续内容到达补全
    source.compact();
}





相关推荐

  1. 【深入理解 ByteBuf 二】对象池设计模式概述

    2024-04-22 00:02:02       36 阅读
  2. NIO非阻塞模式

    2024-04-22 00:02:02       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-22 00:02:02       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-22 00:02:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-22 00:02:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-22 00:02:02       20 阅读

热门阅读

  1. 代码随想录算法训练营day41

    2024-04-22 00:02:02       15 阅读
  2. Mysql优化

    2024-04-22 00:02:02       13 阅读
  3. spring的refresh

    2024-04-22 00:02:02       14 阅读
  4. 如何防止服务器被攻击

    2024-04-22 00:02:02       16 阅读
  5. CSS 预处理器

    2024-04-22 00:02:02       14 阅读
  6. CSS 伪元素和伪类的用法和区别

    2024-04-22 00:02:02       18 阅读
  7. 开发语言漫谈-rust

    2024-04-22 00:02:02       14 阅读
  8. C++ 多线程

    2024-04-22 00:02:02       12 阅读
  9. git远程仓库拉取超过1G报错解决办法

    2024-04-22 00:02:02       15 阅读
  10. Android 一键唤醒应用

    2024-04-22 00:02:02       17 阅读