前面我们讲的读写操作,都是通过一个buffer完成的,NIO还支持通过多个Buffer(即Buffer数组)完成读写操作,即Scattering和Gathering。看NIO服务端代码(这里还没有使用到selector,所以是单线程,只考察Buffer数组的使用):
package com.bruce.nio;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
/**
* 前面我们讲的读写操作,都是通过一个buffer完成的,NIO还支持通过多个Buffer(即Buffer数组)完成读写操作,即Scattering和Gathering
*/
public class SocketChannelBuffers {
public static void main(String[] args) throws Exception{
//使用ServerSocketChannel 和 SocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
InetSocketAddress inetSocketAddress = new InetSocketAddress(7000);
//绑定端口到socket,并启动
serverSocketChannel.socket().bind(inetSocketAddress);
//创建buffer数组
ByteBuffer[] byteBuffers = new ByteBuffer[2];
byteBuffers[0] = ByteBuffer.allocate(5);
byteBuffers[1] = ByteBuffer.allocate(3);
//等待客户端连接
SocketChannel socketChannel = serverSocketChannel.accept();
int messageLength = 8; //假定从客户端接受8个字节
//循环的读取
while(true){
long byteRead = 0;
while (byteRead < messageLength) {
long l = socketChannel.read(byteBuffers);
byteRead += l; //累计读取的字节数
System.out.println("byteRead = " + byteRead);
//使用流打印,看看当前这个buffer的position和limit
Arrays.asList(byteBuffers).stream().map(buffer -> "position=" +
buffer.position() + ", limit=" + buffer.limit()).forEach(System.out::println);
}
//将所有的buffer进行flip
Arrays.asList(byteBuffers).forEach(buffer -> buffer.flip());
//将数据读出显示到客户端
long bytewrite = 0;
while(bytewrite < messageLength){
long l = socketChannel.write(byteBuffers);
bytewrite += l;
}
//将所有的buffer进行clean
Arrays.asList(byteBuffers).forEach(buffer -> buffer.clear());
System.out.println("byteRead = " + byteRead + ", bytewrite = "
+ bytewrite + ", messageLength = " + messageLength);
}
}
}
使用telnet模拟客户端,发送8个字节给服务端,执行结果如下