【Netty】NIO 缓冲区 ( Buffer ) 分散 Scattering 与 聚合 Gathering 操作

举报
韩曙亮 发表于 2022/01/11 01:22:34 2022/01/11
【摘要】 文章目录 I . 缓冲区 ( Buffer ) 分散 Scattering 与 聚合 Gathering 概念II . 缓冲区 ( Buffer ) 分散 Scattering 与 聚合 Gath...





I . 缓冲区 ( Buffer ) 分散 Scattering 与 聚合 Gathering 概念



1 . 分散 Scattering 对应缓冲区写入 : 通道 ( Channel ) 向 缓冲区数组 中写出数据 , 按照索引从第 0 个缓冲区 ( Buffer ) 开始, 依次写入数据 ;

缓冲区 ( Buffer ) 分散 ( Scattering ) 对应方法 : 这是一类方法 , 有很多 , 这里只举一个例子说明 ;

public long read(ByteBuffer[] dsts) throws IOException;

  
 
  • 1

2 . 聚合 Gathering 对应缓冲区读取 : 通道 ( Channel ) 从 缓冲区数组 中读取数据 , 按照索引从第 0 个缓冲区 ( Buffer ) 开始, 依次读取数据 ;

缓冲区 ( Buffer ) 聚合 ( Gathering ) 对应方法 : 这是一类方法 , 有很多 , 这里只举一个例子说明 ;

public long write(ByteBuffer[] srcs) throws IOException;

  
 
  • 1


分散 Scattering 与 聚合 Gathering 都是 通道 ( Channel ) 对 缓冲区数组 ( Buffer[] ) 进行读写的操作 ;





II . 缓冲区 ( Buffer ) 分散 Scattering 与 聚合 Gathering 示例 ( 客户端 )



客户端需求 : 本节演示代码的重心在服务器端 , 服务器端演示 分散 聚合 的具体操作 , 客户端只是演示 网络套接字 流程 , 这里客户端使用 BIO , 使用 TCP 协议进行简单的数据发送 ;


package kim.hsl.bio;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket();
            InetSocketAddress inetSocketAddress =
                    new InetSocketAddress(
                            Inet4Address.getLocalHost(),   //本机IP地址
                            8888                      //端口号
                    );
            System.out.println("客户端开始连接 ...");
            //此处会阻塞等待连接成功
            socket.connect(inetSocketAddress);
            System.out.println("客户端连接成功");
            //连接成功后, 开始执行后续操作
            socket.getOutputStream().write("Hello World".getBytes());
            System.out.println("客户端写出 Hello World 成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

这是之前的示例中使用过的 , 这里在用一次 , 实现的功能 就是 连接目标 IP 地址的 8888 端口 , 发送 “Hello World” 字符串给服务器 , 之后退出 ;





III . 缓冲区 ( Buffer ) 分散 Scattering 与 聚合 Gathering 示例 ( 服务器端 )



1 . 示例需求 : 服务器端使用多个 缓冲区 ( Buffer ) 组成的数组 , 进行读写数据 , 客户端上传的数据 通过 套接字通道 ( SocketChannel ) 写出到 缓冲区数组中 , 服务器端再使用 文件通道 ( FileChannel ) 将数据写出到本地文件中 ;


2 . 示例分析 :


① 缓冲区数组 : ByteBuffer[] buffers = new ByteBuffer[2]; , 创建一个缓冲区数组 , 将这两个缓冲区数组作为读写操作的载体 , 读取数据时就涉及到了缓冲区的 聚合 操作 , 写出数据时 , 就涉及到了 分散 操作 ;

② 分散 Scattering : socketChannel.read(buffers); , 这里直接将数据读取存放到了 缓冲区数组中 , 是将数据分散放入缓冲区数组 , 涉及到 缓冲区 分散 操作 ;

③ 聚合 Gathering : fcOut.write(buffers); , 这里将两个缓冲区的数据 写出到了文件中 , 将分散的数据输入到一个文件中 , 涉及到 缓冲区 聚合 操作 ;

④ 注意缓冲区翻转操作 : 先读取数据 , 之后必须调用 flip() 方法翻转缓冲区 , 然后再写出数据 , 否则会出错 ;


3 . 示例代码 :


package kim.hsl.nio;

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 * 分散 ( Scattering ) 与 聚合 ( Gathering ) 示例
 *
 * 分散 ( Scattering ) : 通道 ( Channel ) 向 缓冲区数组 中写出数据,
 *                       按照索引从第 0 个缓冲区 ( Buffer ) 开始, 依次写入数据
 * 聚合 ( Gathering ) : 通道 ( Channel ) 从 缓冲区数组 中读取数据,
 *                      按照索引从第 0 个缓冲区 ( Buffer ) 开始, 依次读取数据
 *
 * 使用 服务器套接字通道 ( ServerSocketChannel ) 和 套接字通道 ( SocketChannel ) 进行聚合演示
 * 使用 文件通道 ( FileChannel ) 进行分散演示
 *
 * @author han
 *
 */
public class BufferDemo4 {
    public static void main(String[] args) {

        try {
            //1 . 创建 ServerSocketChannel, 绑定本地端口
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            InetSocketAddress inetSocketAddress = new InetSocketAddress(8888);
            serverSocketChannel.socket().bind(inetSocketAddress);

            //2 . 创建 2 个 ByteBuffer, 并放入数组中
            ByteBuffer[] buffers = new ByteBuffer[2];
            buffers[0] = ByteBuffer.allocate(4);
            buffers[1] = ByteBuffer.allocate(8);

            //3 . ServerSocketChannel 阻塞等待客户端连接, 该方法执行后一直阻塞
            SocketChannel socketChannel = serverSocketChannel.accept();

            //4 . 阻塞读取数据, 将数据读取到 buffers 缓冲区数组中的缓冲区中
            socketChannel.read(buffers);

            //5 . 将两个 缓冲区 flip 翻转一下, position 设置为 0
            buffers[0].flip();
            buffers[1].flip();

            //6 . 将读取到的数据写出到文件中
            FileOutputStream fos = null;
            try {
                //1 . FileChannel 可以从 FileOutputStream 中获取
                fos = new FileOutputStream("file4.txt");

                //2 . 创建 FileChannel , 从 FileInputStream / FileOutputStream 中可以获取到
                //FileChannel 是抽象类 , 实际类型是 FileChannelImpl
                FileChannel fcOut = fos.getChannel();

                //3 .  将读取到的数据写出到文件中
                fcOut.write(buffers);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if(fos != null)
                        fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

4 . 执行 服务器端 与 客户端 程序 : 一定要按照顺序执行 , 先启动服务器端 , 再启动客户端 ;


① 启动服务器端 : 先运行服务器端 ;

② 启动客户端 : 再运行客户端 ;

客户端开始连接 ...
客户端连接成功
客户端写出 Hello World 成功

  
 
  • 1
  • 2
  • 3

③ 查看服务器端文件写出结果 :

在这里插入图片描述

文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。

原文链接:hanshuliang.blog.csdn.net/article/details/106373087

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。