博客
关于我
netty底层——nio知识点 ByteBuffer+Channel+Selector
阅读量:794 次
发布时间:2023-02-15

本文共 3923 字,大约阅读时间需要 13 分钟。

Nio编程入门:从基础到实践

Nio三大组件

在Nio编程中,Channel、Buffer和Selector是核心组件,它们共同构成了Nio的非阻塞I/O模型。

Channel(数据通道)

Channel 是数据在Nio中流动的核心载体。与传统的输入输出流不同,Channel 是双向的数据通道,可以同时进行读写操作。例如,Client可以通过Channel与Server进行数据交互。

Buffer(缓冲区)

在数据传输过程中,数据需要暂时存储。Buffer 作为缓冲区,用于临时存储从Channel读取或写入的数据。常见的Buffer实现是 ByteBuffer。

Selector(选择器)

Selector 的作用是管理多个Channel。当一个Channel发生读写事件时,Selector会通知线程进行处理。这种机制避免了传统线程模型中单个线程处理多个客户端连接的问题,提高了效率。

ByteBuffer详解

ByteBuffer 是Nio中最常用的缓冲对象。它的使用需要遵循特定的步骤和模式。

ByteBuffer的内部结构

ByteBuffer有三个重要属性:

  • Capacity:缓冲区的容量。
  • Position:当前读写位置。
  • Limit:读写限制。

ByteBuffer的切换模式

  • flip():切换为读模式。
  • clear():切换为写模式。
  • compact():将未读取的数据向前移动,切换为写模式。

ByteBuffer的使用步骤

  • 写入数据:channel.read(buffer);
  • 切换读模式:buffer.flip();
  • 读取数据:buffer.get();
  • 切换写模式:buffer.clear();buffer.compact();
  • ByteBuffer的常用方法

    • 读取数据

      • buffer.get();
      • buffer.get(Byte[] byte);
      • buffer.rewind();
      • buffer.make(); + buffer.reset();
    • 写入数据

      • buffer.put();
      • channel.write(buffer);

    ByteBuffer的实际应用

    字符串与ByteBuffer互转

    在实际开发中,经常需要将字符串与ByteBuffer之间进行转换。

    // 字符串转换为ByteBufferByteBuffer buffer = ByteBuffer.allocate(16);buffer.put("hello".getBytes());buffer.flip();// 读取数据System.out.println(buffer.get()); // 输出"h"// ByteBuffer转换为字符串String str = StandardCharsets.UTF_8.decode(buffer).toString();

    ###黏包半包问题处理

    当网络数据传输过程中出现黏包或丢包时,可以通过ByteBuffer进行重新组合。

    public class ByteBufferContestTest {    private static ByteBuffer messageBuffer;    public static void main(String[] args) {        messageBuffer = ByteBuffer.allocate(20);        ByteBuffer buffer = ByteBuffer.allocate(32);        buffer.put("Hello,World\nI'm hushang\nHo".getBytes());        split2(buffer);        buffer.put("w are you?\n".getBytes());        split2(buffer);    }    private static void split2(ByteBuffer buffer) {        buffer.flip();        for (int i = 0; i < buffer.limit(); i++) {            if (buffer.get(i) == '\n') {                int length = i + 1 - buffer.position();                ByteBuffer target = ByteBuffer.allocate(length);                for (int j = 0; j < length; j++) {                    target.put(buffer.get(j));                }                target.flip();                System.out.println(StandardCharsets.UTF_8.decode(target).toString());            }        }        buffer.compact();    }}

    文件编程

    FileChannel操作

    FileChannel可以通过FileInputStream、FileOutputStream或RandomAccessFile获取。

    // 读取文件ByteBuffer buffer = ByteBuffer.allocate(1024);channel.read(buffer);// 写入文件buffer.flip();channel.write(buffer);

    文件传输

    实现文件传输可以使用transferTo()方法。

    long size = channel1.size();long left = size;while (left > 0) {    left -= channel1.transferTo(left, left, channel2);}

    Path和Files操作

    Path和Files类用于处理文件路径和文件操作。

    Path source = Paths.get("D:/aaa/bb...");System.out.println(path.normalize());
    // 创建目录Files.createDirectory(Paths.get("E:/1bbb/测试创建文件夹"));// 拷贝文件Files.copy(Path source, Path target);// 移动文件Files.move(Path source, Path target, StandardCopyOption.ATOMIC_MOVE);// 删除文件Files.delete(Path path);

    网络编程

    阻塞模式

    传统的Socket编程是基于阻塞模式的。

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8080));List
    socketChannelList = new ArrayList<>();while (true) { SocketChannel socketChannel = serverSocketChannel.accept(); socketChannelList.add(socketChannel); System.out.println("客户端成功连接服务器!!!");}

    非阻塞模式

    Nio提供了非阻塞编程模式,避免了单线程处理多个连接的问题。

    Selector selector = Selector.open();selector.register(channel, new ByteBuffer());while (!selector.isClosed()) {    try {        int n = selector.select();        for (int i = 0; i < n; i++) {            SelectionKey key = selector.selectedKeys()[i];            if (key.isReadable()) {                ByteBuffer buffer = (ByteBuffer) key.attachment();                buffer.flip();                int bytesRead = channel.read(buffer);                if (bytesRead > 0) {                    System.out.println("读取了" + bytesRead + "字节数据");                }            }        }    } catch (IOException e) {        e.printStackTrace();    }}

    转载地址:http://opcfk.baihongyu.com/

    你可能感兴趣的文章
    Navicat因导入的sql文件中时间数据类型有参数而报错的原因(例:datetime(3))
    查看>>
    Navicat如何连接MySQL
    查看>>
    navicat怎么导出和导入数据表
    查看>>
    Navicat(数据库可视化操作软件)安装、配置、测试
    查看>>
    ndk特定版本下载
    查看>>
    NDK编译错误expected specifier-qualifier-list before...
    查看>>
    Neat Stuff to Do in List Controls Using Custom Draw
    查看>>
    Necurs僵尸网络攻击美国金融机构 利用Trickbot银行木马窃取账户信息和欺诈
    查看>>
    NeHe OpenGL教程 07 纹理过滤、应用光照
    查看>>
    NeHe OpenGL教程 第四十四课:3D光晕
    查看>>
    Neighbor2Neighbor 开源项目教程
    查看>>
    neo4j图形数据库Java应用
    查看>>
    Neo4j图数据库_web页面关闭登录实现免登陆访问_常用的cypher语句_删除_查询_创建关系图谱---Neo4j图数据库工作笔记0013
    查看>>
    Neo4j图数据库的介绍_图数据库结构_节点_关系_属性_数据---Neo4j图数据库工作笔记0001
    查看>>
    Neo4j安装部署及使用
    查看>>
    Neo4j电影关系图Cypher
    查看>>
    Neo4j的安装与使用
    查看>>
    Neo4j(2):环境搭建
    查看>>
    Neo4j(4):Neo4j - CQL使用
    查看>>
    NEO改进协议提案1(NEP-1)
    查看>>