背景
- scatting和gathering研究的是一个buffer数组。在这个buffer数组中持有多个Buffer实例,每个Buffer都是独立的,都有自己独立的capacity,limit,position值。
- buffer数组中的buffer实例唯一相互联系的地方就是:从第一个buffer数组中的Buffer实例开始,依次读满后才往后面的Buffer实例移动。写也是如此。从数组中的第一个Buffer实例中的数据依次往外写。
过程
- 测试代码
public static void main(String[] args) throws Exception{
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
InetSocketAddress address = new InetSocketAddress(8899);
serverSocketChannel.socket().bind(address);
int messageLength = 2 + 3 + 4;
ByteBuffer[] buffers = new ByteBuffer[3];
buffers[0] = ByteBuffer.allocate(2);
buffers[1] = ByteBuffer.allocate(3);
buffers[2] = ByteBuffer.allocate(4);
SocketChannel socketChannel = serverSocketChannel.accept();
while (true) {
int bytesRead = 0;
while (bytesRead < messageLength) {
long r = socketChannel.read(buffers);
bytesRead += r;
System.out.println("bytesRead: " + bytesRead);
Arrays.asList(buffers).stream().
map(buffer -> "position:" + buffer.position() + ", limit:" + buffer.limit()).
forEach(System.out::println);
Arrays.asList(buffers).forEach(buffer -> {
buffer.flip();
});
int bytesWrite = 0;
while (bytesWrite < messageLength) {
long bw = socketChannel.write(buffers);
bytesWrite += bw;
}
Arrays.asList(buffers).forEach(buffer -> {
buffer.clear();
});
System.out.println("bytesRead:" + bytesRead + ", " + "bytesWrite:" + bytesWrite + "," + "messageLength:" + messageLength);
}
}
}
- 关键代码
ByteBuffer[] buffers = new ByteBuffer[3];
buffers[0] = ByteBuffer.allocate(2);
buffers[1] = ByteBuffer.allocate(3);
buffers[2] = ByteBuffer.allocate(4);
有一个buffer类型的数组,数组中有3个Buffer实例,每个的容量是2,3,4.
-
测试一(发送7个字符到服务端,最后一个回车符也算一个字符)
客户端:
服务端:
最后一个Buffer实例,它的容量是4,但是只使用了2个。 -
测试二(发送9个字符到服务端)
客户端:
服务端:
-
测试三(发送10个字符到服务端)
客户端:
服务端:
使用场景
- 它的特性是天然地使用一个数组(Buffer类型的数组),而数组中就是Buffer实例,每个Buffer实例可以装独立的数据,相互之间没有任何关系。比如HTTP中请求头,请求体数据采用buffer数组来装。这个buffer数组持有两个独立的Buffer实例,一个装请求头数据,另一个装请求体数据。
小结
- scattering和gathering描述的Buffer类型的数组,数组中的实例是一个个Buffer实例,每个实例有独立的属性(mark,limit,position,capacity)。
- 通过3个测试,理解多个Buffer实例放在一个数组中的工作过程是怎样的。