Java NIO:Scattering和Gathering的理解

示例解析

package com.leolee.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

/**
 * @ClassName ScatteringAndGatheringTest
 * @Description: TODO
 * @Author LeoLee
 * @Date 2020/9/20
 * @Version V1.0
 **/
public class ScatteringAndGatheringTest {

    public static void test () throws IOException {

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        InetSocketAddress inetSocketAddress = new InetSocketAddress(8899);
        serverSocketChannel.socket().bind(inetSocketAddress);

        SocketChannel socketChannel = serverSocketChannel.accept();

        int messageLength = 2 + 3 + 4;

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

        while (true) {
            int bytesRead = 0;

            while (bytesRead < messageLength) {
                long r = socketChannel.read(byteBuffers);
                bytesRead += r;

                System.out.println("bytesRead:" + bytesRead);
                System.out.println("after read,show every buffer:");

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

            Arrays.asList(byteBuffers).forEach(byteBuffer -> {
                byteBuffer.flip();
            });

            long bytesWrite = 0;
            while (bytesWrite < messageLength) {
                long w = socketChannel.write(byteBuffers);
                bytesWrite += w;
            }

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

            System.out.println("bytesRead:" + bytesRead + ",bytesWrite:" + bytesWrite + ",messageLength:" + messageLength);

        }
    }

    public static void main(String[] args) throws IOException {

        ScatteringAndGatheringTest.test();
    }
}

代码解读:

  • 通过开启一个 NIO 的服务端 socket 通道作为一个接收客户端发送 socket 数据的接收器,运行后进入死循环模拟服务器不退出
  • 定义了 messageLength 作为消息接收的限制长,以及一个 buffer 数组,这个buffer数组包含三个 buffer,大小分别是 2、3、4
  • socket 数据接收器启动之后,会将接收到的数据读取并原封不动的写回客户端

运行结果:

启动程序,并且通过 telnet 命令来模拟请求

telnet localhost 8899,连接成功后,输入 abcd12345

服务端打印如下:

bytesRead:1
after read,show every buffer:
position:1,limit:2,capacity:2
position:0,limit:3,capacity:3
position:0,limit:4,capacity:4
bytesRead:2
after read,show every buffer:
position:2,limit:2,capacity:2
position:0,limit:3,capacity:3
position:0,limit:4,capacity:4
bytesRead:3
after read,show every buffer:
position:2,limit:2,capacity:2
position:1,limit:3,capacity:3
position:0,limit:4,capacity:4
bytesRead:4
after read,show every buffer:
position:2,limit:2,capacity:2
position:2,limit:3,capacity:3
position:0,limit:4,capacity:4
bytesRead:5
after read,show every buffer:
position:2,limit:2,capacity:2
position:3,limit:3,capacity:3
position:0,limit:4,capacity:4
bytesRead:6
after read,show every buffer:
position:2,limit:2,capacity:2
position:3,limit:3,capacity:3
position:1,limit:4,capacity:4
bytesRead:7
after read,show every buffer:
position:2,limit:2,capacity:2
position:3,limit:3,capacity:3
position:2,limit:4,capacity:4
bytesRead:8
after read,show every buffer:
position:2,limit:2,capacity:2
position:3,limit:3,capacity:3
position:3,limit:4,capacity:4
bytesRead:9
after read,show every buffer:
position:2,limit:2,capacity:2
position:3,limit:3,capacity:3
position:4,limit:4,capacity:4
bytesRead:9,bytesWrite:9,messageLength:9

可以看到 telnet 发送的9个长度的消息,被顺序的存入了三个数组中,当一个 buffer 满了之后,才会存入下一个 buffer,这就是Scattering,之后服务端又将所有数据返回给客户端,如下:

这就是 Gathering。

理解

对于 NIO 中这样的有趣设计,其实是很有必要的。比如,当在使用自定义协议的时候,不同大小的有序 buffer 序列(buffer 数组)可以轻而易举的告诉开发者,每一个 buffer 是代表什么信息,并不需要特别的解析。

猜你喜欢

转载自blog.csdn.net/qq_25805331/article/details/108691831