天天看点

NIO学习笔记(4) -- Scatter/GatherNIO学习笔记(4) – Scatter/Gather

NIO学习笔记(4) – Scatter/Gather

​ 分散(scatter)从 Channel 中读取是指在读操作时将读取的数据写入多个 buffer 中。因此,Channel 将从 Channel 中读取的数据 “分散(scatter)” 到多个 Buffer 中。

​ 聚集(gather)写入 Channel 是指在写操作时将多个 buffer 的数据写入同一个 Channel,因此,Channel 将多个 Buffer 中的数据 “聚集(gather)” 后发送到 Channel。

​ scatter / gather 经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息,你可能会将消息体和消息头分散到不同的 buffer 中,这样你可以方便的处理消息头和消息体。

1. cattering Reads

Scattering Reads 是指数据从一个 channel 读取到多个 buffer 中。如下图描述:

NIO学习笔记(4) -- Scatter/GatherNIO学习笔记(4) – Scatter/Gather

2.Gathering Writes

​ Gathering Writes 是指数据从多个 buffer 写入到同一个 channel。如下图描述

NIO学习笔记(4) -- Scatter/GatherNIO学习笔记(4) – Scatter/Gather

代码示例:

public class NioTest11 {

    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 绑定8899端口
        InetSocketAddress address = new InetSocketAddress(8899);

        // 启动服务器
        serverSocketChannel.socket().bind(address);

        int messageeLength = 2 + 3 + 4;

        ByteBuffer[] byteBuffers = new ByteBuffer[3];

        byteBuffers[0] = ByteBuffer.allocate(2);
        byteBuffers[1] = ByteBuffer.allocate(3);
        byteBuffers[2] = ByteBuffer.allocate(4);

        // 等待客户端连接
        SocketChannel socketChannel = serverSocketChannel.accept();

        while (true) {
            int byteRead = 0;
            while (byteRead < messageeLength) {
                // 这里是直接读取的byteBuffers
                final long r = socketChannel.read(byteBuffers);
                byteRead += r;

                System.out.println("byteRead :" + byteRead);

                Arrays.asList(byteBuffers).stream().map(buffer -> "position:" + buffer.position() + ",limit" + buffer.limit())
                        .forEach(System.out::println);
            }
            Arrays.asList(byteBuffers).forEach(byteBuffer -> byteBuffer.flip());

            int byteWritten = 0;
            // 等读的数量到达messageeLength长度才发送给客户端
            while (byteWritten < messageeLength) {
                // 这里是直接写的byteBuffers
                long w = socketChannel.write(byteBuffers);
                byteWritten += w;
            }

            Arrays.asList(byteBuffers).forEach(byteBuffer -> byteBuffer.clear());

            System.out.println("byteRead:" + byteRead + ",byteWritten" + byteWritten + ",messageeLength" + messageeLength);
        }
    }
}

           

验证代码:

>./nc localhost 8899  // 表示连接到本地8899端口,这里使用的是ServerSocketChannel,所以为长连接
>88888888	// 输入八位数 + 回车,刚刚死九尾,所以说这里服务端会返回一个88888888