Buffer API学习
文章目录一、Buffer 读API二、字符串和Buffer的转换三、分散读取四、集中写五、黏包和半包现象出现原因1 黏包2 半包解决办法一、Buffer 读APIBufferrewind() 不改变极限,把位置设置为0,表示从头开始读取。public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(1
一、Buffer 读API
- Buffer rewind() 不改变极限,把位置设置为0,表示从头开始读取。
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put(new byte[]{'a','b','c','d'});
buffer.flip();
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
buffer.rewind();
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
}
结果是:a、b、c、d、a、b
调用rewind之后,从头开始再次读取。
- Buffer reset() 将此缓冲区的位置重置为先前标记的位置。
- Buffer mark() 将此缓冲区的标记设置在其位置。
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put(new byte[]{'a','b','c','d'});
buffer.flip();
buffer.get();
buffer.get();
ByteBufferUtil.debugAll(buffer);
//此时position=2。标记此位置
buffer.mark();
buffer.get();
buffer.get();
//这里读取完毕,此时从标记位置开始读取
buffer.reset();
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
}
结果是c、d
- abstract byte get(int index) 获取制定位置的字节,不改变位置。
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put(new byte[]{'a','b','c','d'});
buffer.flip();
System.out.println((char) buffer.get(2)); //c
ByteBufferUtil.debugAll(buffer);
}
二、字符串和Buffer的转换
public static void main(String[] args) {
ByteBuffer buffer1 = ByteBuffer.allocate(16);
buffer1.put("hello".getBytes());
debugAll(buffer1);
}
此时没有切换到读模式。所以要想读取,还是调用flip()方法;
使用StandardCharsets也可以构造buffer。而且极限根据字节大小设置。并且自动切换到读模式。
public static void main(String[] args) {
ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("hello");
debugAll(buffer2);
}
ByteBuffer buffer3 = ByteBuffer.wrap("hello".getBytes());
debugAll(buffer3);
ByteBuffer.wrap的作用和StandardCharsets一样的。也是自动切换读取模式。
StandardCharsets.UTF_8.decode转化buffer为字符串。
//转化字符串
String s=StandardCharsets.UTF_8.decode(buffer2).toString();
System.out.println(s);
//针对buffer1.因为没有转化读取模式,所以这里需要调用flip
buffer1.flip();
String s2=StandardCharsets.UTF_8.decode(buffer1).toString();
System.out.println(s2);
三、分散读取
假设word1.txt中有数据onetwothree。我们需要一次性读取。
public static void main(String[] args) {
//twr Java7快速关闭
try (FileChannel channel = new RandomAccessFile("word1.txt", "r").getChannel()) {
ByteBuffer buffer1 = ByteBuffer.allocate(3);
ByteBuffer buffer2 = ByteBuffer.allocate(3);
ByteBuffer buffer3 = ByteBuffer.allocate(5);
//一次性读取
channel.read(new ByteBuffer[]{buffer1,buffer2,buffer3});
buffer1.flip();
buffer2.flip();
buffer3.flip();
debugAll(buffer1);
debugAll(buffer2);
debugAll(buffer3);
} catch (IOException e) {
}
}
四、集中写
将one、two、three一次性写入buffer.
public static void main(String[] args) {
ByteBuffer buffer1 = StandardCharsets.UTF_8.encode("one");
ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("two");
ByteBuffer buffer3 = StandardCharsets.UTF_8.encode("three");
try (FileChannel channel = new RandomAccessFile("word2.txt", "rw").getChannel()) {
channel.write(new ByteBuffer[]{buffer1,buffer2,buffer3});
} catch (IOException e) {
}
}
五、黏包和半包
现象
网络上有多条数据发送给服务端,数据之间使用 \n 进行分隔
但由于某种原因这些数据在接收时,被进行了重新组合,例如原始数据有3条为
Hello,world\n
I’m Nyima\n
How are you?\n
变成了下面的两个 byteBuffer (粘包,半包)
Hello,world\nI’m Nyima\nHo
w are you?\n
出现原因
1 黏包
发送方在发送数据时,并不是一条一条地发送数据,而是将数据整合在一起,当数据达到一定的数量后再一起发送。这就会导致多条信息被放在一个缓冲区中被一起发送出去
2 半包
接收方的缓冲区的大小是有限的,当接收方的缓冲区满了以后,就需要将信息截断,等缓冲区空了以后再继续放入数据。这就会发生一段完整的数据最后被截断的现象
解决办法
通过get(index)方法遍历ByteBuffer,遇到分隔符时进行处理。注意:get(index)不会改变position的值
记录该段数据长度,以便于申请对应大小的缓冲区
将缓冲区的数据通过get()方法写入到target中
调用compact方法切换模式,因为缓冲区中可能还有未读的数据
public class BufferNianBao {
public static void main(String[] args) {
//模拟黏包的半包的读取
ByteBuffer buffer = ByteBuffer.allocate(32);
// 模拟粘包+半包
buffer.put("Hello,world\nI'm Gosaint\nHo".getBytes());
// 调用split函数处理
split(buffer);
buffer.put("w are you?\n".getBytes());
split(buffer);
}
private static void split(final ByteBuffer buffer) {
buffer.flip();
for(int i=0;i<buffer.limit();i++){
if (buffer.get(i)=='\n') {
//遇到\n,表示一个完整的语句。写入的buffer
int length=i+1-buffer.position();
ByteBuffer target = ByteBuffer.allocate(length);
//将数据写入target
for (int j = 0; j < target.limit(); j++) {
// 将buffer中的数据写入target中
target.put(buffer.get());
}
debugAll(target);
}
}
//读取完毕之后读取剩余的部分,不能使用clear。clear会从头开始的
buffer.compact();
}
}
更多推荐
所有评论(0)