NIO简单入门笔记【一】 三大组件

news2024/10/7 18:27:14

前言
👏作者简介:我是笑霸final,一名热爱技术的在校学生。
📝个人主页:个人主页1 || 笑霸final的主页2
📕系列专栏 JAVA专栏
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏

本博客视频教程地址链接 黑马程序员Netty全套教程, netty深入浅出Java网络编程教程

学习目标:

例如:

  • 认识 Channel 、Buffer、Selector

学习内容:

一 Channel 、 Buffer 和 Selector

channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前的 stream 要么是输入,要么是输出,channel 比 stream 更为底层
在这里插入图片描述
常见的 Channel 有

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

buffer 则用来缓冲读写数据,常见的 buffer 有

  • ByteBuffer
    • MappedByteBuffer
    • DirectByteBuffer
    • HeapByteBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer
  • CharBuffer

selector 的作用就是配合一个线程来管理多个 channel,获取这些 channel 上发生的事件,这些 channel 工作在非阻塞模式下,不会让线程吊死在一个 channel 上。适合连接数特别多,但流量低的场景(low traffic)

selector 版
selector
thread
channel
channel
channel

调用 selector 的 select() 会阻塞直到 channel 发生了读写就绪事件,这些事件发生,select 方法就会返回这些事件交给 thread 来处理

二 ByteBuffer 与Channel的使用

用 FileChannel 来读取文件内容 。有一普通文本文件 data.txt,内容为

123456789@asdcvbnhj

demo01

//读取文件
        try(FileChannel channel = new FileInputStream("nettyStd/netty-demo/src/main/resources/data.txt").getChannel()){
            //准备缓冲区
            ByteBuffer allocate = ByteBuffer.allocate(10);//缓存区
            //向缓冲区里面写数据
            // 将字节序列从此通道读取到给定缓冲区中。
            //从此通道的当前文件位置开始读取字节,
           	// 然后使用实际读取的字节数更新文件位置。
            // 否则,此方法的行为与接口中 ReadableByteChannel 
            //指定的完全一样。
            channel.read(allocate);

            //切换模式
            allocate.flip();

            while (allocate.hasRemaining()){
                byte b = allocate.get();
                //byte b1 = allocate.get(0); 
                //注意带参数的不会影响读指指针的移动
                System.out.print((char) b);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

输出内容

123456789@


demo02

 try(FileChannel channel = new FileInputStream("nettyStd/netty-demo/src/main/resources/data.txt").getChannel()){

            ByteBuffer buffer = ByteBuffer.allocate(10);



            while (true){
            //会根据实际大小来读 返回-1则读取完毕
                int read = channel.read(buffer);
                log.info("当前 read的值 {} \t",read);
                if(read== -1)break;

                buffer.flip();//切换模式

                while (buffer.hasRemaining()){
                    byte b = buffer.get();
                    System.out.print((char) b);

                }
                System.out.println();
                //清除此缓冲区。位置设置为零,限制设置为容量,标记被丢弃
                buffer.clear();

            }



        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

总结 ByteBuffer 正确使用姿势

  • 向 buffer 写入数据,例如调用 channel.read(buffer)
  • 调用 flip() 切换至读模式
  • 从 buffer 读取数据,例如调用 buffer.get()
  • 调用 clear() 或 compact() 切换至写模式: compact 方法,是把未读完的部分向前压缩,然后切换至写模式

2.1 ByteBuffer 结构

ByteBuffer 有以下重要属性:

  • capacity 总容量
  • position
  • limit

1.写模式下,position 是写入位置,limit 等于容量
2.flip() 动作发生后 (读模式),position 切换为读取位置,limit 切换为读取限制
在这里插入图片描述

三、ByteBuffer 的常见方法

1、分配空间

ByteBuffer.allocate(10)

2.写入数据

  • 调用 channel 的 read() 方法
FileChannel channel = new FileInputStream("资源").getChannel();
 channel.read(allocate);
  • 调用 buffer 自己的 put 方法
 buffer.put("my name is xbfinal".getBytes());

3.从 buffer 读取数据

  • 调用 channel 的 write 方法
    将字节序列从给定缓冲区写入此通道
    int writeBytes = channel.write(buf);

  • 调用 buffer 自己的 get 方法
    byte b = buf.get();
    get() 方法会让 position 读指针向后走,如果想重复读取数据,可以调用 rewind 方法将 position 重新置为 0或者调用 get(int i) 方法获取索引 i 的内容,它不会移动读指针

分散读取 Scattering Reads

有一个文本文件 3parts.tx内容如下:onetwothree
demo

try (RandomAccessFile file = new RandomAccessFile("helloword/3parts.txt", "rw")) {
    FileChannel channel = file.getChannel();
    ByteBuffer a = ByteBuffer.allocate(3);
    ByteBuffer b = ByteBuffer.allocate(3);
    ByteBuffer c = ByteBuffer.allocate(5);
    channel.read(new ByteBuffer[]{a, b, c});
    a.flip();
    b.flip();
    c.flip();
    while (a.hasRemaining()){
    //allocate.get(0); 注意带参数的不会影响读指指针的移动
         System.out.print((char)  a.get());
     }
    while (b.hasRemaining()){
         System.out.print((char)  b.get());
     }
     while (c.hasRemaining()){
         System.out.print((char)  c.get());
     }
     a.clear();
     b.clear();
     c.clear();
    
} catch (IOException e) {
    e.printStackTrace();
}

分散写 Gathering Writes

try (RandomAccessFile file = new RandomAccessFile("helloword/3parts.txt", "rw")) {
    FileChannel channel = file.getChannel();
    ByteBuffer d = ByteBuffer.allocate(4);
    ByteBuffer e = ByteBuffer.allocate(4);
    channel.position(11);

    d.put(new byte[]{'f', 'o', 'u', 'r'});
    e.put(new byte[]{'f', 'i', 'v', 'e'});
    d.flip();
    e.flip();
    channel.write(new ByteBuffer[]{d, e});
} catch (IOException e) {
    e.printStackTrace();
}

四、字符串与 ByteBuffer 互转

字符串 转 byte

  • 1.getBytes()
  • 2 ByteBuffer.wrap
  • 3 StandardCharsets.UTF_8.encode()
	log.info("字符串  ====》 byte  ");

    log.info("1.getBytes() ");
    ByteBuffer allocate = ByteBuffer.allocate(1024);
//  allocate.put(MY_STR.getBytes()); 默认使用系统自带的编码方式
    allocate.put(MY_STR1.getBytes(StandardCharsets.UTF_8));//不会自动转化为读模式
    allocate.flip();
   while (allocate.hasRemaining()){
         System.out.print( (char) allocate.get());
    }
   System.out.println("\n=================");

  log.info(" 2.wrap ");
  //会自动转化为读模式
  ByteBuffer wrap = ByteBuffer.wrap(MY_STR1.getBytes());
  while (wrap.hasRemaining()){
      System.out.print( (char) wrap.get());
 }
  System.out.println("\n=================");

  log.info(" 3.Charset ");
  //会自动转化为读模式
  ByteBuffer encode = StandardCharsets.UTF_8.encode(MY_STR1);  while (encode.hasRemaining()){
      System.out.print( (char) encode.get());
  }
  System.out.println("\n=================");

byte 转 字符串

		log.info(" byte  ====》 字符串   ");
        log.info(" 3.Charset ");
        //会自动转化为读模式
        ByteBuffer encode1 = StandardCharsets.UTF_8.encode(MY_STR);
        //调用这个之前一定要让ByteBuffer为读模式
        String s = StandardCharsets.UTF_8.decode(encode1).toString();
        System.out.println(s);

五、练习

网络上有多条数据发送给服务端,数据之间使用 \n 进行分隔
但由于某种原因这些数据在接收时,被进行了重新组合,例如原始数据有3条为

  • Hello,world\n
  • world\n
  • my name is xbfinal\n
    变成了下面的两个 byteBuffer (黏包,半包)
  • hello\nworld\nmy name i
  • s xbfinal!\n

现在要求你编写程序,将错乱的数据恢复成原始的按 \n 分隔的数据

public class TestByBufferDemo01 {

    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(50);
        buffer.put("hello\nworld\nmy name i".getBytes()); //粘包 半包

        hello(buffer);//输出一部分
        buffer.put("s xbfinal!\n".getBytes());// 半包
        hello(buffer);
    }

    public static void hello(ByteBuffer buffer){
        //进来先转化为读模式
       buffer.flip();
       for (int i = buffer.position(); i <buffer.limit() ; i++) {
            if('\n' == buffer.get(i)){
                // 我们先存入新的ByteBuffer
                int len = i -buffer.position();
                ByteBuffer allocate = ByteBuffer.allocate(len);
                for (int j = 0; j < len; j++) {
                    allocate.put(buffer.get());
                }
                //输出
                allocate.flip();
                for (int j = 0; j < len; j++) {
                    System.out.print((char) allocate.get());
                }
            }
        }
        //这里由于有粘包 半包。不能用clear
        buffer.compact();
    }

}

学习产出:

  • CSDN 技术博客 1 篇
  • 笑霸final的私人技术博客 1 篇 链接http://www.xbfinal.top点此跳转

🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/529448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python 基础(十三):函数

❤️ 博客主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;Python 入门核心技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; 文章目录 一、创建函数二、调用函数三、向函数传递参数3.1、形参和实参3.2、多参函数3.3、参数的…

【C生万物】 指针和数组笔试题汇总 (上)

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; &#x1f449; 专栏&#xff1a;《C生万物 | 先来学C》&#x1f448; 前言&#xff1a; 在学习完初级和进级的指针之后&#xff0c;为了检验掌握程度&#xff0c;这里出一期指…

MYSQL 之 Redis配置与优化

&#xff08;一&#xff09;关系数据库和非关系数据库 关系库数据库Oracle &#xff0c;mysql &#xff0c;sql&#xff0c;server&#xff0c;microsoft Access &#xff0c;postgresql 以上数据库必须先建表在设计表的结构&#xff0c;然后存储的时侯按表的结构去存&#x…

微信小程序入门01-工具的下载安装及模板的安装

小程序开发现在已经有多种模式了&#xff0c;有使用uniapp开发的&#xff0c;使用微信开发者工具开发的&#xff0c;还有低代码工具也支持开发小程序的。 在众多开发模式中&#xff0c;使用官方开发者工具开发也是一种形式。本篇我们就介绍一下如何用微信开发者工具搭建小程序…

【MATLAB第32期】基于MATLAB的降维/全局敏感性分析/特征排序/数据处理分类问题MATLAB代码实现(持续更新)

【MATLAB第32期】基于MATLAB的降维/全局敏感性分析/特征排序/数据处理分类问题MATLAB代码实现(持续更新) 本文敏感性分析主要分析分类问题&#xff08;fisher、rf、arf、nca等&#xff09;。 一、降维方法&#xff08;分类&#xff09; 常见的降维方法&#xff1a; 常见的敏…

2023,8种必备Selenium编写自动化用例的技巧(建议收藏)

在开始自动化时&#xff0c;您可能会遇到各种可能包含在自动化代码中的方法&#xff0c;技术&#xff0c;框架和工具。有时&#xff0c;与提供更好的灵活性或解决问题的更好方法相比&#xff0c;这种多功能性导致代码更加复杂。在编写自动化代码时&#xff0c;重要的是我们能够…

Jangow

Jangow 1.环境准备 靶场地址&#xff1a;https://www.vulnhub.com/entry/jangow-101,754/下载好靶机之后直接使用VMware Workstation Pro虚拟机导入环境&#xff0c;启动即可&#xff0c;将网段设置为NAT模式攻击机&#xff1a;kali&#xff08;192.168.80.180&#xff09;靶…

【电厂用 多功能数码显示 HJY-F931B/D交流三相电压继电器JOSEF约瑟】

用途 HJY系列数字式交流电压继电器为瞬时动作特性&#xff0c;用于发电机&#xff0c;变压器&#xff0c;输电线路的继电保护装 置中作为过压或欠压的闭锁启动元件。 安装结构 导轨安装9&#xff0c;导轨安装E两种结构方式&#xff0c;具体尺寸请参考外型尺寸图。特点 (1). 采…

局域网内使用的多人协同编辑文档的软件哪个好?对比5款主流平台

支持局域网内多人协同编辑文档的软件或平台哪个好&#xff1f;PingCode 、Confluence 等知识库工具和腾讯文档、飞书文档等都支持多人协作编辑&#xff0c;怎么选&#xff1f;这是企业团队在找文档管理工具最常见的问题。 支持局域网内协同编辑的软件可以分为两个大类&#xf…

azkaban介绍

目录 为什么需要工作流调度系统 什么是azkaban azkaban适用场景 azkaban特点 常见的工作流调度系统 azkaban和Ooize特性对比 azkaban的架构 azkaban调度的任务有可能有那些类型 总结 为什么需要工作流调度系统 一个完整的大数据分析系统&#xff0c;必然由很多任务单…

基于显扬科技3D视觉相机的医疗试管分拣系统

行业现状&#xff1a; 医疗试管分拣是医疗行业中的一个重要环节&#xff0c;指将医疗实验室或生物技术研究中的试管按照一定的规则进行分拣&#xff0c;并对试管的类型、位置、数量等信息进行识别和管理。 随着医疗技术的不断发展和诊断治疗的精细化&#xff0c;医疗试管分拣…

Python之selenium关于Chrome驱动位置和闪退的问题

目录 一、Chromedriver放置的位置二、浏览器闪退 一、Chromedriver放置的位置 背景&#xff1a;之前由于Chrome浏览器自动升级后&#xff0c;导致驱动与浏览器不匹配&#xff0c;自己也不知道问题出在哪儿&#xff0c;花费了我大量时间去排查&#xff0c;所以接下来记录一些。…

Linux ps -A 和 ps -ef

Linux ps &#xff08;英文全拼&#xff1a;process status&#xff09;命令用于显示当前进程的状态&#xff0c;类似于 windows 的任务管理器 ps -A | grep xx 显示xx所有的进程 ps -ef | grep xx 显示xx在一个终端的所有进程 注意这里ef 其实可以拆开理解 e 是显示所有进…

oracle报错ORA-12514

问题&#xff1a;oracle使用服务名orcl登录不成功&#xff0c;并且报错 ORA-12514, TNS:listener does not currently know of service requested in conn原因分析&#xff1a; ORA-12514 错误通常表示 Oracle 数据库监听器无法识别客户端请求的服务名称。这可能是由于以下原因…

什么是ERP、APS和MES

01 先来说说ERP与MES的区别 ERP&#xff1a;企业资源计划 一天中午&#xff0c;丈夫在外给家里打电话&#xff1a;“亲爱的老婆&#xff0c;晚上想带几个同事回家吃饭可以吗&#xff1f;”&#xff08;订货意向&#xff09; 丈夫&#xff1a;“6个人&#xff0c;我们7点左右回…

【计算机视觉】如何利用 CLIP 做简单的人脸任务?(含源代码)

文章目录 一、数据集介绍二、源代码 结果三、代码逐行解读 一、数据集介绍 CELEBA 数据集&#xff08;CelebFaces Attributes Dataset&#xff09;是一个大规模的人脸图像数据集&#xff0c;旨在用于训练和评估人脸相关的计算机视觉模型。该数据集由众多名人的脸部图像组成&a…

【MySQL】MySQL索引--聚簇索引和非聚簇索引的区别

文章目录 前言1.聚簇索引和非聚簇索引的概念2.两者详细介绍2.1 聚簇索引2.2 非聚簇索引 3. 两者的区别3.1 数据存储方式3.2 二级索引查询 前言 1.聚簇索引和非聚簇索引的概念 数据库表的索引从数据存储方式上可以分为聚簇索引和非聚簇索引两种。“聚簇”的意思是数据行被按照…

【Java|golang】1072. 按列翻转得到最大值等行数

给定 m x n 矩阵 matrix 。 你可以从中选出任意数量的列并翻转其上的 每个 单元格。&#xff08;即翻转后&#xff0c;单元格的值从 0 变成 1&#xff0c;或者从 1 变为 0 。&#xff09; 返回 经过一些翻转后&#xff0c;行与行之间所有值都相等的最大行数 。 示例 1&#…

使用TensorFlow构建,绘制和解释人工神经网络

使用 Python 进行深度学习&#xff1a;神经网络&#xff08;完整教程&#xff09; 使用TensorFlow构建&#xff0c;绘制和解释人工神经网络 总结 在本文中&#xff0c;我将展示如何使用Python构建神经网络&#xff0c;以及如何使用可视化和创建模型预测解释器向业务解释深度学习…

【PCIE】pcie设备协议分析和crash后定位

分析RP Headerlog在协议中位置 能力集寄存器协议字段 HeaderLog字段偏移以及各字段含义 headerLog和协议的对应入截图中内容 completer id就是完成的ID&#xff0c;对应的BDF &#xff0c;如下图 b5:00.0 AECap寄存器 其中 first error pointer 含义&#xff1a; 这里有专…