3.NIO-ByteBuffer常用方法,分散读集中写,黏包半包
1.2.3、ByteBuffer常见方法
public class TestBufferRead {
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put(new byte[]{'a', 'b', 'c', 'd'});
buffer.flip();
buffer.get(new byte[4]);//读四个字节
ByteBufferUtil.debugAll(buffer);
buffer.rewind();//从头开始读
System.out.println((char) buffer.get());
ByteBufferUtil.debugAll(buffer);
buffer.mark();//记录position位置
System.out.println((char) buffer.get());
buffer.reset();//将position复位到mark位置
System.out.println((char) buffer.get());
ByteBufferUtil.debugAll(buffer);
System.out.println((char) buffer.get(3));//根据下标读取,position不变
ByteBufferUtil.debugAll(buffer);
}
}
分配空间
//返回的是HeapByteBuffer类型ByteBuffer 分配的堆内存
allocate();
//返回的是HDirectByteBuffer类型ByteBuffer 分配的是只直接的物理内存,读写快,分配慢
ByteBuffer.allocateDirect(16);
从buffer读取
//从buffer读,写入channel
channel.write(buffer);
//直接读,返回byte
buffer.get();
get方法会让position向后移,如果想要重复读取数据
- rewind() 方法会将position=0
- get(int i) 通过索引获取内容,position不会移动
mark reset
- mark 是在读取时,做一个标记
- reset 即使 position 改变,只要调用 reset 就能回到 mark 的位置
get(int index)
- 读取指定下标数据
字符串与Buffer互转
public class TestByteBufferString {
public static void main(String[] args) {
//1.字符串转byteBuffer
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put("hello".getBytes());
ByteBufferUtil.debugAll(buffer);
//2.Charset 切换到读模式
ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("hello");
ByteBufferUtil.debugAll(buffer2);
//3.wrap 切换到读模式
ByteBuffer buffer3 = ByteBuffer.wrap("hello".getBytes());
ByteBufferUtil.debugAll(buffer3);
//decode只能转读模式
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer2);
System.out.println(charBuffer.toString());
}
}
1.2.4、分散读
//分散读取,可以将数据填充至多个 buffer
public class TestScatteringReads {
public static void main(String[] args) {
try {
FileChannel channel = new RandomAccessFile("data.txt", "r").getChannel();
ByteBuffer buffer1 = ByteBuffer.allocate(4);
ByteBuffer buffer2 = ByteBuffer.allocate(5);
ByteBuffer buffer3 = ByteBuffer.allocate(5);
channel.read(new ByteBuffer[]{buffer1, buffer2, buffer3});
buffer1.flip();
buffer2.flip();
buffer3.flip();
ByteBufferUtil.debugAll(buffer1);
System.out.println(buffer1.get());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
1.2.5、集中写
//集中写,可以将多个 buffer 的数据填充至 channel
public class TestGatherWrites {
public static void main(String[] args) {
ByteBuffer buffer1 = StandardCharsets.UTF_8.encode("hello");
ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("world");
ByteBuffer buffer3 = StandardCharsets.UTF_8.encode("你好");
try {
RandomAccessFile file = new RandomAccessFile("a.txt", "rw");
FileChannel channel = file.getChannel();
channel.write(new ByteBuffer[]{buffer1, buffer2, buffer3});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
1.2.6、黏包,半包
网络上有多条数据发送给服务端,数据之间使用 \n 进行分隔
但由于某种原因这些数据在接收时,被进行了重新组合,例如原始数据有3条为
- Hello,world\n
- I'm zhangsan\n
- How are you?\n
变成了下面的两个 byteBuffer (黏包,半包)
- Hello,world\nI'm zhangsan\nHo
- w are you?\n
解决:
public class TestByteBufferExam {
public static void main(String[] args) {
ByteBuffer source = ByteBuffer.allocate(64);
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 buffer) {
buffer.flip();
for (int i = 0; i < buffer.limit(); i++) {
if ('\n' == buffer.get(i)) {
int length = i - buffer.position() + 1;
ByteBuffer allocate = ByteBuffer.allocate(length);
for (int j = 0; j < length; j++) {
allocate.put(buffer.get());
}
ByteBufferUtil.debugAll(allocate);
}
}
buffer.compact();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
2021-10-12 阿里云的这群疯子