Netty入门指南之NIO Channel详解

news2024/11/26 19:27:01

作者简介:☕️大家好,我是Aomsir,一个爱折腾的开发者!
个人主页:Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客
当前专栏:Netty应用专栏_Aomsir的博客-CSDN博客

文章目录

  • 参考文献
  • 前言
  • Channel
    • 简介
    • 常见Channel
    • Channel获取方式
  • Buffer简介
  • 演示案例
    • IO流
    • Channel
      • 错误案例
      • 改进案例
      • 注意
  • 总结

参考文献

  • 孙哥suns说Netty
  • Netty官方文档

前言

从本篇文章开始,我们将深入学习 NIO(非阻塞I/O)编程的相关内容,从头到尾详尽分析,包括Selector和Reactor模型,这将为我们后续学习Netty等更高层次的网络编程库打下坚实的基础。NIO编程的核心元素主要包括ChannelBuffer

NIO编程使用Channel来进行通信。在服务端,我们还引入了Selector选择器,它帮助我们主动监控客户端的Channel,确保这些Channel能够正常通信(即正常连接且没有阻塞)。通过监控客户端的请求链路,Selector的作用是,一旦发现某个客户端阻塞,它可以将分配给该客户端的线程重新分配给其他可用客户端,这样一个线程就能为多个客户端提供服务。需要注意的是,每个客户端都拥有自己独立的Channel,不共享一个Channel。这篇文章将深入学习和理解Channel的概念,为后续的内容打下坚实的基础。

Channel

简介

Channel是一种用于IO通信的管道,类似于传统的InputStreamOutputStream。然而,与传统IO流不同,其中有输入流和输出流的方向性,NIO中的Channel是 无方向性。在传统IO开发中,为了读取文件并在JVM中进行操作后将结果写回文件,我们需要一个InputStream输入流将文件读入JVM,然后使用OutputStream输出流将结果写回文件。这些流是单向的,每个用于特定的目的。而在NIO中,Channel既可以用于读取数据,也可以用于写入数据,这为通用的双向数据传输提供了更大的灵活性
在这里插入图片描述

常见Channel

  • 文件IO操作
    • FileChannel:读和写文件中的数据
  • 网络IO操作
    • ServerSocketChannel:监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接创建一个SocketChannel
    • SocketChannel:通过TCP读写网络中的数据
    • DatagramChannel:通过UDP读写网络中的数据

Channel获取方式

  • 文件IO操作
    • FileInputStream/FileOutputStream获取
    • RandonAccessFile获取
  • 网络通信
    • Socket获取
    • ServerSocket获取
    • DatagramSocket获取
FileChannel channel = new FileInputStream(TestNIO1.class.getClassLoader().getResource("data.txt").getFile()).getChannel();

FileChannel channel = new RandomAccessFile("data.txt", "rw").getChannel();

Buffer简介

因在下一篇文章中,我们将详细讲解Buffer,因为它是NIO中的一个非常核心的概念。掌握好Buffer对于理解后续的内容,包括Netty,至关重要。

Buffer可以被看作是JVM内存中的一块区域,它类似于一个缓冲区。在传统的流通信中,我们通常使用字节数组来装载接收到的数据。Buffer也类似于这个字节数组,但不同之处在于它具有读写指针,用于标识内存中的数据是用于读取还是写入。这一特性使得Buffer非常适用于NIO中的数据处理

演示案例

IO流

如下是使用Stream流的方式的进行读操作

public class TestNIO1 {
    private static final Logger log = LoggerFactory.getLogger(TestNIO1.class);

    public static void main(String[] args) throws IOException {
        // 创建输入流
        InputStream inputStream = TestNIO1.class.getClassLoader().getResourceAsStream("data.txt");

        // 创建缓冲区
        byte[] bytes = new byte[1024];

        // 读取数据到缓冲区
        while (inputStream.read(bytes) != -1){
            String s = new String(bytes);
            log.info("s = {}", s);
        }
    }
}

Channel

错误案例

在下面的案例中,我们设置Buffer的大小为10个字节。但是,如果我们尝试读取一个13字节的数据流,那么后面的3个字节将一直保留在缓冲区中,无法读取。动态调整Buffer的大小可能不是一个明智的选择,因为这会引入复杂性。

为了解决这个问题,我们可以采用改进案例中的方法。不再固定Buffer的大小,而是使用循环不断读取,直到所有数据被消耗。这种方式可以有效地处理不定长度的数据,而不需要频繁地调整缓冲区大小

public class TestNIO1 {
    private static final Logger log = LoggerFactory.getLogger(TestNIO1.class);

    public static void main(String[] args) throws IOException {
       // 1.创建Channel通道 - FileChannel
       FileChannel channel = new FileInputStream("/Users/aomsir/MyStudyProject/Java/Netty/netty-basic-01/data.txt").getChannel();

       // 2.创建Buffer缓冲区,容量为10字节,具体根据文件编码来定
       ByteBuffer buffer = ByteBuffer.allocate(10);

       while (true) {
           // 3.把channel读取的数据放入buffer,读完以后返回的是-1
           int read = channel.read(buffer);
           if (-1 == read) {
               break;
           }

           // 4.设置buffer为读模式,代表程序从buffer中读取数据
           buffer.flip();

           // 5.循环读取缓冲区数据
           while (buffer.hasRemaining()) {
               byte b = buffer.get();
               System.out.println((char) b);
           }

           // 6.操作之后将buffer设置为写模式
           buffer.clear();
       }
    }
}

改进案例

改进案例非常简单,我们可以通过循环复用Buffer来处理未读取的数据。这意味着我们不需要不断调整Buffer的大小,而是在一个循环中不断读取数据,直到所有数据都被处理。这种方法能够有效地解决数据流长度不确定的情况,确保不会漏掉任何数据。同时上一个错误案例没有做异常处理,此改进版本做了异常处理。

public class TestNIO2 {
    private static final Logger log = LoggerFactory.getLogger(TestNIO2.class);

    public static void main(String[] args) {

        FileChannel channel = null;
        try {

            // 1.通过FileInputStream获取对应的FileChannel管道
            channel = new FileInputStream(TestNIO1.class.getClassLoader().getResource("data.txt").getFile()).getChannel();

            // 2.创建Buffer缓冲区,容量为10字节,具体根据文件编码来定
            ByteBuffer buffer = ByteBuffer.allocate(10);

            while (true) {
                // 3.让buffer从channel中读取数据,如果没有读到数据则返回-1
                int read = channel.read(buffer);
                if (-1 == read) {
                    break;
                }

                // 4.设置buffer为读模式,代表程序从buffer中读取数据
                buffer.flip();

                // 5.循环读取缓冲区数据
                while (buffer.hasRemaining()) {
                    byte b = buffer.get();
                    log.info("(char)b = {}", (char)b);
                }

                // 6.操作之后将buffer设置为写模式,方便下一次写入数据
                buffer.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (channel != null) {
                try {
                    channel.close();
                } catch (IOException e) {
                    throw new RuntimeException();
                }
            }
        }
    }
}

注意

在Buffer中,通过使用flip()方法,我们可以切换为读操作的模式。这表示其他程序可以从Buffer中读取数据。另一方面,要切换为写操作模式,我们可以使用clear()方法。这表示后续的程序可以向Buffer中写入数据,或者从Channel中读取数据并放入Buffer中进行进一步处理。

总结

在本篇文章中,我们将深入研究NIO中的Channel,探讨其双向可读可写的特性,介绍一些常见的Channel类型以及它们的创建方式。我们还将详细演示FileChannel的使用,而在后续的内容中,我们将逐渐学习SocketChannel、ServerSocketChannel等更多内容。这些知识将有助于我们更好地理解和充分利用NIO中的通道,为后续的学习和应用奠定坚实的基础。

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

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

相关文章

【1107】

interface是面向对象编程语言中接口操作的关键字,功能是把所需成员组合起来,用来封装一定功能的集合。 它好比一个模板,在其中定义了对象必须实现的成员,通过类或结构来实现它。 接口不能直接实例化,即ICount icnew iC…

回归模型原理总结及代码实现

前言 本文将介绍回归模型算法,并总结了一些常用的除线性回归模型之外的模型,其中包括一些单模型及集成学习器。 保序回归、多项式回归、多输出回归、多输出K近邻回归、决策树回归、多输出决策树回归、AdaBoost回归、梯度提升决策树回归、人工神经网络、…

openGauss Meetup(合肥站)精彩回顾 | openGauss合肥用户组正式成立

由openGauss社区、天津南大通用数据技术股份有限公司联合主办的“openGauss Meetup • 合肥站”已于11月4日落下帷幕,此次活动邀请到数据库行业专家与行业同仁共同探讨数据库技术发展创新、数据库产业发展与落地、数据库周边工具构建、生态共建等内容,推…

IDEA项目下不显示target目录或者target目录不完整没有新添加的资源,idea隐藏target目录

文章目录 一、前言二、idea隐藏target目录2.1、idea隐藏target目录2.2、git提交时隐藏target目录 三、idea下显示target目录3.1、解决idea下不显示target目录问题3.2、target显示目录不完整 一、前言 在idea-2020.1.4版本下讲解idea怎么显示或隐藏target目录。 需要知道:如果…

执行mysql-community-libs-8.1.0-1.el8.x86_64.rpm报错依赖检测失败

目录 1.错误信息 2.解决方法 1.错误信息 我是在VMware虚拟机18上的Centos8上的,安装MySQL8.1.0,执行mysql-community-libs-8.1.0-1.el8.x86_64.rpm报错 [rootlocalhost mysql8.1.0]# rpm -ivh mysql-community-libs-8.1.0-1.el8.x86_64.rpm 警告&…

rvt文件发三维服务

一、所需工具 SuperMap iDesktop、Revit、SuperMap-Revit插件、SuperMap iServer。 二、操作流程 BIM数据发三维服务: 1、Revit中打开BIM数据,附加模块—UDB SuperMap Export。 2、打开SuperMap IDesktop,数据源—打开文件型数据源&…

Java入门篇 之 类与对象

本篇碎碎念:博主作为一个三本学生,庆幸自己上了个本科,但是在支付高昂学费的时候认识到,自己要好好学习,不好好学习,难道以后给人端盘子咩;无论是专科还是本科,都不可以自暴自弃&…

洛谷P2196 [NOIP1996 提高组] 挖地雷【动态规划思路分析】看完直接举一反三!

P2196 [NOIP1996 提高组] 挖地雷 前言题目题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 题目分析注意事项 代码后话额外测试用例样例输入 #2样例输出 #2 王婆卖瓜 题目来源 前言 我发现我是天才,只做了三道动态规划的类型题就感觉我已经炉火纯青了。大…

如何实现生产质量精细化管理?

导 读 ( 文/ 1528 ) 在现代制造业中,实现生产质量的精细化管理对企业的竞争力至关重要。本文将介绍三个关键步骤,包括建立全面质量管理体系、采用数据驱动的质量监控和实时反馈机制,以及持续改进和员工培训,帮助企业实现生产质量的…

[答疑]大老二和德州扑克-属性值没变,状态怎么变了

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 邬俊杰 2023-10-31 21:20 课上说状态是由属性值决定的,比如身高>170算高,某人身高175,算高。如果规则改了,身高>180算高&#xf…

即插即用篇 | YOLOv8 引入Super Token Sampling ViT | 《CVPR 2023 最新论文》

论文地址:https://arxiv.org/abs/2211.11167 代码地址:https://github.com/hhb072/STViT 视觉变换器已经在许多视觉任务中取得了令人印象深刻的性能。然而,它在捕捉浅层的局部特征时可能会受到高度冗余的影响。因此,引入了局部自注意力或早期卷积,这些方法牺牲了捕捉长距…

生产问题分析:批量执行慢,根据日志进行分析。

1.首先拿到日志,查看批量执行的时间段为36:58-42:24 2.截取时间段为36:58-42:24的日志内容。 3.从该批量的第一个代码看起,sql会打印在日志里,查找第一个sql,对照代码一个个看下去。 4.发现两个sql执行的时间间隔特别长&#xff1…

云尘 命令执行系列

第一题 system <?php include "flag.php";if (isset($_POST[cmd])) {system($_POST[cmd]); }show_source(__FILE__);代码如上 system($_POST[cmd]); POST请求发送一个名为 cmd 的参数&#xff0c;然后将该参数的值传递给系统命令执行函数 system()&#xff0c…

高并发下Redis缓存与数据库双写一致性问题原理分析和解决方案

目录 一、什么是缓存与数据库双写不一致性二、常见保证高并发下双写一致性方案2.1、延迟双删&#xff08;不可靠&#xff09;2.2、分布式读写锁&#xff08;可靠&#xff09;2.3、MQ异步消费&#xff08;不可靠&#xff09;2.4、订阅数据库变更日志&#xff08;不可靠&#xff…

2023年十大地推拉新接单平台和网推接单平台,都是一手单

2023年做拉新推广的地推人员&#xff0c;一定不要错过这十个接单平台&#xff0c;助你轻松找到一手单&#xff0c;这10个平台分别是&#xff1a; 主推&#xff1a;“聚量推客” 一手官签接单平台 一手官方邀请码 000000 1. 聚量推客&#xff1a; “聚量推客”汇聚了众多市场…

怎样选择适合自己的ITSM软件?

市场上ITSM解决方案琳琅满目&#xff0c;每种解决方案都有其优点和缺点。这使选择决策过程变得复杂&#xff0c;当组织机构决定投资ITSM软件时&#xff0c;很难如愿选择到一款最适合自己的帮助台软件。 而小编有一套系统的决策方法&#xff0c;可以帮助您简化评估过程&#xff…

Dart(一):Dart入门

Dart入门 Dart安装创建项目安装依赖&#xff08;以http为例&#xff09;依赖库查询地址添加依赖编写运行示例 dart常用命令引用核心库、自定义库、第三方库数据类型Numbers (int, double)Strings (String)Booleans (bool)Lists (List)Maps (Map)Sets (Set)Null (null)Records (…

Django初窥门径-自定义附件存储模型

前言 Django自带了一个名为FileField的字段&#xff0c;用于处理文件上传。然而&#xff0c;有时我们需要更多的控制权&#xff0c;例如定义文件的存储路径、文件名以及文件类型。在本篇文章中&#xff0c;我们将探讨如何自定义Django附件存储模型。 创建attachment应用 pyt…

Unity3d C#实现编辑器不运行状态下执行的脚本

第一章方式&#xff1a; 函数前面 [ContextMenu("Play")] &#xff0c;Inspector面板右键调用 第二种方式&#xff1a; OnValidate() &#xff0c;值改变自动执行 using UnityEngine; using System.Linq;public class NightController : MonoBehaviour {pub…

只需十分钟,快速入门Python3!

文章目录 前言1. 原始数据类型和运算符2. 变量和集合3. 流程控制和迭代器4. 函数5. 类6. 模块7. 高级用法关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小…