天天看點

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