Netty入门指南之NIO Channel详解

作者简介:☕️大家好,我是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.mfbz.cn/a/128488.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一天获4奖!大势智慧荣获2023测绘科学技术奖一等奖、地理信息科技进步奖一等奖、测绘科技创新优秀单位、地理信息产业最具成长性企业

11月9日,第一届中国测绘地理信息大会暨北斗应用博览会颁奖仪式在德清国际展览中心重磅揭幕。 大势智慧凭借《空天地多源融合实景三维建模关键技术及工具体系》项目斩获“2023年测绘科学技术奖一等奖” 凭借《大型复杂文化遗产多尺度精细化三维建模关键技术与应用》…

HBuilderX 运行Android App项目至雷电模拟器

一、下载安装HBuilderX HBuildeX官网 安装最新的正式版,或者点击历史版本查看更多版本;【ps:Alpha版本为开发版,功能更多,但是也不稳定,属于测试版本】 直接将压缩包解压,运行HBuildeX即可。 二…

供应原厂电流继电器 - HBDLX-21/3 整定电流范围0.1-1.09A AC220V

HBDLX系列型号: HBDLX-20/1零序过电压继电器;HBDLX-20/2零序过电压继电器 HBDLX-20/3零序过电压继电器;HBDLX-20/4零序过电压继电器 HBDLX-20/5零序过电压继电器;HBDLX-21/1零序过电压继电器 HBDLX-21/2零序过电压继电器&#xf…

清华陆向谦教授提到的纽约时报的一篇文章-探讨学历贬值

文章内容来自: https://www.nytimes.com/2017/11/01/education/edlife/stem-jobs-industry-careers.html By Steve Lohr Nov. 1, 2017 阅读简体中文版閱讀繁體中文版 The national priority in education can be summed up in a four-letter acronym: STEM. And…

【Git】GUI图形化界面的使用SSH协议IDEA集成Git

🥳🥳Welcome Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于Git的相关操作吧 目录 🥳🥳Welcome Huihuis Code World ! !🥳🥳 一. GUI图形化界面的使用 1.使用Gui​ 2.常…

WPS的JS宏基础(四)——运算符

1、算术运算符 运算符是在编写代码时,最常用的符号。从本节课开始,运算符主要分为:算术运算符、连接运算符、比较运算符、逻辑运算符、赋值运算符等。我们将讲解这些常见的运算符,本节课讲解的是算术运算符。 符号作用加-减*乘/…

Windows系统Python语言环境下通过SDK进行动作捕捉数据传输

NOKOV度量动作捕捉系统可以与市面上主流的操作系统和编程语言实现通信。可以在Windows系统Python语言环境下通过SDK进行动作捕捉数据传输。 一、形影软件设置 1、切换到后处理模式 2、加载一段刚体数据 3、打开软件设置 4、将网卡地址选择为10.1.1.198 5、勾选上"使用SD…

Linux arm64异常简介和系统调用过程

文章目录 一、异常简介1.1 Exception levels1.2 异常类型 二、系统调用简介2.1 SVC指令2.2 VBAR2.3 系统调用保存现场2.4 系统调用返回 三、Linux 内核分析参考资料 一、异常简介 在ARM64体系架构中,异常是处理器在执行指令时可能遇到的不寻常情况或事件。这些异常…

实现智慧工地的高效建筑管理,数据分析起着关键作用!

智慧工地是利用物联网、云计算、大数据等技术,实现对建筑工地实时监测、管理和控制的一种新型建筑管理方式。 智慧工地架构: 1、终端层:充分利用物联网技术、移动应用、智能硬件设备提高现场管控能力。通过RFID、传感器、摄像头、手机等终端…

银行电子回单p图软件,建设农业邮政工商招商,易语言回执单快照截图

这次分享的还是通过易语言的画板自动绘画一个回执单的功能,套用的是网上一个回执单模版,我加了水印,防止被别有用心的人利用,然后一共我插入了5个图片资源,单选框选定后画板上面的图片会自动被替换为对应的图片模版&am…

Qframework 中超级方便的kitres

using QFramework; using System.Collections; using System.Collections.Generic; using UnityEngine;public class TestResKit : MonoBehaviour {ResLoader mResLoader ResLoader.Allocate();private void Awake(){}/// <summary>/// 每一个需要加载资源的单元(脚本,界…

机器学习——朴素贝叶斯

目录 一、贝叶斯方法 背景知识 贝叶斯公式 二、朴素贝叶斯原理 判别模型和生成模型 1&#xff0e;朴素贝叶斯法是典型的生成学习方法 2&#xff0e;朴素贝叶斯法的基本假设是条件独立性 3&#xff0e;朴素贝叶斯法利用贝叶斯定理与学到的联合概率模型进行分类预测 用于文…

零代码编程:用ChatGPT批量提取flash动画swf文件中的mp3

文件夹&#xff1a;C:\迅雷下载\有声绘本_flash[淘宝-珍奥下载]\有声绘本 flash&#xff0c;里面有多个flash文件&#xff0c;怎么转换成mp3文件呢? 可以使用swfextract工具从Flash动画中提取音频&#xff0c;下载地址是http://www.swftools.org/download.html&#xff0c;也…

接口自动化测试之Fiddler使用教程

一、Fiddler 简介 Fiddler工具介绍 Fiddler是一个通过代理的方式来进行抓包工具&#xff0c;运行时会在本地建立一个代理服务&#xff0c;默认地址&#xff1a;127.0.0.1:8888。Fiddler开启之后&#xff0c;配置本机代理&#xff0c;再打开IE浏览器&#xff0c;IE的PROXY会自…

具名挂载和匿名挂载

匿名卷挂载 &#xff1a; -v 的时候只指定容器内的路径 如下面这个&#xff1a;/etc/nginx 1.docker run -d -P --name nginx -v /etc/nginx nginx 2.查看所有卷 docker volume ls 这里发现&#xff0c;这就是匿名挂载&#xff0c;只指定容器内的路径&#xff0c;没有指定…

刷题学习记录BUUCTF

[极客大挑战 2019]RCE ME1 进入环境直接就有代码 <?php error_reporting(0); if(isset($_GET[code])){$code$_GET[code];if(strlen($code)>40){die("This is too Long.");}if(preg_match("/[A-Za-z0-9]/",$code)){die("NO.");}eval($co…

如何低门槛开发有趣实用的ZigBee产品?

一、什么是 Zigbee 协议&#xff1f; Zigbee 技术是一种连接距离短、功耗低、复杂程度低、数据传输量低的无线通信技术&#xff0c;其命名灵感源自于蜜蜂在群体中的信息传输。它主要通过网关与互联网进行通信&#xff0c;并嵌入各种智能设备&#xff0c;最终实现自动控制和远程…

射频功率放大器有哪些用途

射频功率放大器是一种专用于放大射频信号的设备&#xff0c;它在现代通信、广播、雷达、无线电频谱监测和科学研究等领域中发挥着重要的作用。射频功率放大器能够将输入的低功率射频信号放大为较高功率的信号&#xff0c;以满足各种应用场景对信号传输距离、质量和稳定性的要求…

基于SSM的博客系统

基于SSM的博客系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringMyBatisSpringMVC工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 热点 博客详情 登录界面 管理员界面 博主界面 摘要 博客系统作为信息传播和分享的重…

Python 解决tkinter的Menu菜单command参数与bind方法共用触发事件

用普通函数作为媒介&#xff0c;使用event_generate()方法模拟触发bind()事件来创建一个模拟的event对象&#xff0c;并将其传递给绑定的事件处理函数。 运行结果 示例代码 import tkinter as tk# 菜单事件 def menuEvent(event):print(event.x, event.y)label.config(textf鼠…
最新文章