Netty—ByteBuffer

原文链接:https://liancode.top/posts/f79db71a.html

ByteBuffer

一、使用

  1. buffer 写入数据,例如调用 channel.read(buffer)
  2. 调用 filp() 切换至读模式
  3. buffer 读取数据,例如调用 buffer.get()
  4. 调用 clear() 或者 compact() 切换至写模式
  5. 重复 1-4 步骤
public class TestByteBuffer {
    public static void main(String[] args) {
        try {
            FileChannel channel = new FileInputStream("src/main/resources/data.txt").getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(10);
            while (channel.read(buffer) != -1){
                buffer.flip();
                while (buffer.hasRemaining()){
                    byte b = buffer.get();
                    System.out.print(" "+ (char) b);
                }
                buffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二、ByteBuffer 结构

1. 属性

  • capacity
  • position
  • limit

image-20210814202959182image-20210815172617805

image-20210815173713178

2. 常见方法

  • 分配空间 :allocate()allocateDirect()
public class TestByteBufferAllocate {
    public static void main(String[] args) {
        /**
         * class java.nio.HeapByteBuffer
         * java 堆内存,读写效率较低,受到 GC 的影响
         * GC 的标记整理算法,会多一次拷贝
         */
        System.out.println(ByteBuffer.allocate(10).getClass());
        /**
         * class java.nio.DirectByteBuffer
         * 直接内存,读写效率高(少一次拷贝),不受 GC 的影响
         * 系统内存的分配效率低,netty对其进行了优化,使用不当会造成内存泄露
         * 注:直接内存与 ByteBuffer 是虚引用,ByteBuffer 被 GC 回收后,直接内存也会被清理
         */
        System.out.println(ByteBuffer.allocateDirect(10).getClass());
    }
}
  • 写入数据

    调用 channelread 方法

    调用 buffer 自己的 put 方法

int readByte = channel.read(buf);
buf.put((byte) 127);
  • 读取数据

    调用 channelwrite 方法

    调用 bufferget 方法

    mark():标记当前 position

    reset():回到标记的位置

int writeByte = channel.write(buf);
buf.get();

get() 方法会让 position 的读指针往后移动,如果需要重复读取数据

  • 调用 rewind 方法将 position 重置为 0
  • 调用 get( int i ) 方法获取索引 i 的内容,指针不会移动
  • 字符串与 ByteBuffer 互转
ByteBuffer buf = StandardCharsets.UTF_8.encode("hello");
ByteBuffer buf2 = ByteBuffer.wrap("hello".getBytes());

String str = StandardCharsets.UTF_8.decode(buf).toString();

3. 处理黏包和拆包

  • 简单方法
public class TestByteBufferExam {
    public static void main(String[] args) {
        ByteBuffer source = ByteBuffer.allocate(32);
        source.put("hello,world\nI'm,zhangsan\nHo".getBytes());
        split(source);
        source.put("w are you?\n".getBytes());
        split(source);
    }

    public static void split(ByteBuffer source) {
        source.flip();
        for (int i = 0; i < source.limit(); i++) {
            if (source.get(i) == '\n') {
                int len = i + 1 - source.position();
                ByteBuffer buffer = ByteBuffer.allocate(len);
                for (int j = 0; j < len; j++) {
                    buffer.put(source.get());
                }
                buffer.rewind();
                System.out.println(StandardCharsets.UTF_8.decode(buffer));
            }
        }
        source.compact();
    }
}

版权声明:本文为weixin_45636641原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。