Java IO流(四)Netty理论[模型|核心组件]

概述

  • Netty是由JBOSS提供的一个Java开源框架,可从Github获取独立项目
  • Netty是一个异步的、基于事件驱动的网络应用框架,用于快速开发可维护、高性能的网络服务器和客户端(摘录官网)
  • Netty所谓的异步是针对用户使用Channel进行IO操作,会立即返回ChannelFuture。但IO操作的任务是提交给了Netty的NIO底层去进行处理,所以我们说Netty的异步事件驱动与Netty底层基于NIO(同步非阻塞)是不矛盾的
  • Netty主要针对在TCP传输协议下,面对Clients端高并发应用;本质属于NIO框架,适用于服务器通讯相关多种应用场景
    • 阿里分布式服务框架Dubbo的RPC框架使用Dubbo协议,而Dubbo协议默认使用Netty作为基础的通信组件,实现节点间内部通信
    • 大数据领域中Hadoop的RPC框架默认采用的就是Netty进行跨节点通信
  • Netty官网版本推荐:目前稳定版为Netty4.x

Netty模型

Netty基于主从Reactor多线程模型做了一定的改进,其中主从Reactor多线程模型中存在多个Reactor

工作原理执行流程

  • Netty中抽象了两组线程池BossGroup和WorkerGroup,都属于NioEventLoopGroup,其中BossGroup负责接收客户端连接,WorkerGroup负责网络读写
    • NioEventLoopGroup属于事件循环组,这个组中包含多个事件循环,每个事件循环是NioEventLoop
    • NioEventLoop表示一个不断循环的执行处理任务的线程,每个NioEventLoop都有一个selector,用于监听绑定在其上socket的网络通讯
  • BossGroup下每个NioEventLoop执行流程
    • 轮询accept事件
    • 处理accept事件,与client建立连接生成NIOSocketChannel,并将其注册到对应worker下NIOEventLoop上的selector
    • 处理任务队列任务,即runAllTasks
  • WorkerGroup下每个NioEventLoop执行流程
    • 轮询read,write事件
    • 在对应NIOSocketChannel中处理read,write I/O事件
    • 处理任务队列任务,即runAllTasks
  • 每个Worker NioEventLoop处理业务时都会交由pipeLine管道处理,pipeline中包含了channel,即通过pipeline可以获取对应channel通道,管道中维护了很多处理业务的Handler处理器

TaskQueue任务队列

BossGroup和WorkerGroup下每个NioEventLoop中都维护了一个TaskQueue,可以用来异步处理比较耗时的任务,TaskQueue中的Task有三种典型使用场景

  • 用户程序自定义普通任务,该任务会提交到TaskQueue
    public class NettyServerHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //读取客户端发送的数据
            //ctx:上下文对象,包含管道pipeline,通道等信息
            //用户程序自定义普通任务
            ctx.channel().eventLoop().execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(10 * 1000); //模拟耗时长的任务
                        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, Client!", CharsetUtil.UTF_8)); //将数据写到缓存并刷新
                    } catch (Exception e) {
                        System.out.println("Exception Info: " + e.getMessage());
                    }
                }
            });
        }
    }
  • 用户自定义定时任务,该任务提交到scheduleTaskQueue
            ctx.channel().eventLoop().schedule(() -> {
                try {
                    Thread.sleep(5 * 1000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, Client!", CharsetUtil.UTF_8)); 
                } catch (Exception e) {
                    System.out.println("Exception Info: " + e.getMessage());
                }
            },5, TimeUnit.SECONDS);
  • 非当前Reactor线程调用Channel的各种方法(常用于推送任务场景)

异步模型

  • 异步和同步相对,指的是当一个异步过程调用发出后,调用者不能立刻得到结果,实际处理这个调用的组件在完成后,会通过状态、通知和回调来通知调用者
  • Netty中的I/O操作是异步的,包括Bind、Write、Connect等会返回一个ChannelFuture
  • Netty的异步模型是建立在future和callback之上的,callback即回调,Future核心思想在于对于处理某些耗时的业务时会立刻返回一个Future(表示异步执行结果,其中通过监听方法检测任务执行情况),通过Future监控该业务处理的过程最终获得I/O操作结果(即Future-Listener机制)
    • Future-Listener机制
      • 当Future对象刚刚创建时,处于非完成状态,调用者可以通过返回的 ChannelFuture来获取操作执行状态,注册监听函数来执行完成后的操作
      • 常见操作方法
        • isDone: 判断当前操作是否完成
        • isSuccess: 判断已完成的当前操作是否成功
        • getCause: 判断当前操作失败的原因
        • isCancelled: 判断已完成的当前操作是否被取消
        • addListener: 用来注册监听器,当前操作已完成,将会通知指定的监听器(如果Future对象已完成,则通知指定的监听器)
      • Future-Listener示例

        ChannelFuture cf = bootstrap.bind(6668).sync(); //绑定指定端口并同步处理
        cf.addListener(new ChannelFutureListener() { //为端口添加监听
        	@Override
        	public void operationComplete(ChannelFuture channelFuture) throws Exception {
        		if (cf.isSuccess()){
        			System.out.println("监听端口成功!");
        		} else{
        			System.out.println("监听端口失败!");
        		}
        	}
        });

核心组件

Netty中根据各组件职责不同可以分为网络通信层、事件调度层、服务编排层

网络通信层核心组件

BootStrap|ServerBootStrap

BootStrap是Netty中客户端启动类,负责客户端启动并连接Netty服务端;ServerBootStrap是服务端启动引导类,负责服务端启动并监听端口;常用方法包括如下

  • group:服务端用来设置BossGroup和WorkerGroup,而对于客户端则是设置一个EventGroup
  • channel:用来设置服务器端的通道类型,如服务器端设置为NioServerSocketChannel类型
  • option:用来给ServerChannel添加配置,如设置线程队列连接个数
  • childOption:用来给接收通道添加配置,如设置活动连接状态
  • handler:该handler作用于BossGroup
  • childHandler:该handler作用于WorkerGroup,设置业务处理类,包括自定义的handler
  • bind:用于服务器端,设置对外暴露的端口号
  • connect:用于客户端,设置连接服务器的ip和端口等信息

Channel

提示:NioSocketChannel和NioServerSocketChannel分别对应客户端和服务端的Channel,两者的直接父类不一致,因此对外提供的功能也是不相同的。比如当发生read事时,NioServerSocketChannel 的主要逻辑就是建立新的连接,而NioSocketChannel则是读取传输的字节进行业务处理

  • Netty中的Channel是完成一系列网络通信的载体
  • Channel可以看成网络编程中的Socket,提供了执行网络异步IO操作API,包括read|write|bind|connect,通过ChannelFuture中已注册的监听器在IO操作成功、失败等回调通知调用结果,大大降低了直接使用Socket类的复杂性
    • Future|ChannelFuture:Netty中所有IO操作都是异步的,不能立刻得知消息是否正确处理,但可以通过Future和ChannelFuture注册监听事件,当操作成功或者失败自动触发注册的监听事件,常用方法如下

      • channel:返回当前正在进行的IO操作的通道
      • sync:等待异步操作执行完毕
  • 通过Channel可获取当前网络连接的通道的状态以及配置参数等
  • 不同协议、不同阻塞类型的连接都有不同的Channel类型与之对应,常用Channel类型如下
    • NioSocketChannel:异步客户端TCP Socket连接
    • NioServerSocketChannel:异步服务器端TCP Socket连接
    • NioDatagramChannel:异步的UDP连接

事件调度层核心组件

EventLoopGroup

就是一个线程池,负责接收I/O请求并分配线程执行处理请求,在Netty服务端中的bossGroup中的线程用来处理新连接的建立,当连接建立后分发给workerGroup,workerGroup中每个线程则都会和唯一的客户端Channel连接进行绑定并处理该Channel上的读、写事件

EventLoop

就相当于线程池中的一个线程

服务编排层核心组件

Channel&&ChannelPipeline&&ChannelHandler关系

ChannelPipeline

  • ChannelPipeline是Handler集合,它负责处理和拦截inbound或者outbound的事件和操作,即用于处理Channel的入站和出站操作
  • Netty中每个Channel都有一个ChannelPipeline与之对应,两者可以互相获取;而且Pipeline维护了一个channelHandlerContext组成的双向链表,并且channelHandlerContext关联一个ChannelHandler
  • 当Channel中发生指定事件时,该事件就会在ChannelPipeline中沿着双向链表进行传播并调用各个ChannelHandler中的指定方法完成相应的业务处理
  • ChannelPipeline常用方法如下
    • addFirst:把业务处理类Handler添加到链表中第一个位置
    • addLast:把业务处理类Handler添加到链表中最后一个位置

提示:Netty正是通过ChannelPipeline这种数据结构为用户提供了自定义业务逻辑的扩展点,用户只需要向ChannelPipeline中添加处理对应业务逻辑的ChannelHandler即可,当指定事件发生时,该ChannelHandler中的对应方法就会进行回调进而实现业务的处理

ChannelHandler

ChannelInboundHandler&&ChannelOutboundHandler分别用来处理读&&写事件
  • ChannelHandler是Netty 中业务处理的核心类,当有 IO 事件发生时,该事件会在ChannelPipeline中进行传播,并依次调用具体的ChannelHandler进行业务处理

ChannInboundHandler

  • 在ChannelInboundHandler中定义了一系列的回调方法,用户可以实现该接口并重写相应的方法来自定义的业务逻辑
    • channelRegistered: 当 Channel 绑定到了对应 Selector 上之后就会进行回调

    • channelActive: 当 Channel调用bind()完成端口绑定之后,channelActive() 方法会进行回调

    • channelRead0

      • 服务端channelRead0
        • 服务端Channel绑定到Selector上时监听的是Accept事件,当客户端有新连接接入时回调channelRead()方法并完成新连接的接入
      • 客户端channelRead0
        • 当服务端处理完Accept事件后会生成一个和客户端通信的Channel,该Channel也会注册到对应的Selector上并监听read事件,当客户端向该Channel中发送数据时就会触发read事件,调用channelRead()方法
    • exceptionCaught:当前ChannelHandler中各回调方法处理过程中若发生异常则回调该方法

ChannelHandlerContext

  • ChannelHandlerContext主要保存了Channel通道、ChannelHandler通道处理者相关信息,它们之间对应关系如下
    • ChannelPipeline与ChannelHandlerContext对应关系: 1:n
    • ChannelHandlerContext与ChannelHandler 对应关系: 1:1
  • ChannelHandlerContext 常用方法如下
    • channel(): 获取当前通道
    • pipeline(): 获取当前管道
    • handler(): 获取当前handler处理器
    • close(): 关闭当前通道
    • writeAndFlush(): 将数据写出到ChannelPipeline管道中

其他

Unpooled类

  • Unpooled是Netty提供的专门操作缓冲区的工具类
  • copiedBuffer:用来设置数据以及字符编码并返回一个ByteBuf对象
    • ByteBuf:Netty中提供的缓冲区,底层就是一个数组
    • ByteBuf不需要调用flip方法进行模式切换,底层通过readerIndex|writerIndex|capactiy将byteBuf分成三个区域
      • 0-readerIndex:表示已经读取的区域
      • readerIndex-writerIndex:可读的区域
      • writerIndex-capactiy:可写的区域

Netty的编码解码机制

Netty提供的编码和解码器包括如下

  • StringEncoder:对字符串数据进行编码
  • ObjectEncoder:对Java对象进行编码
  • StringDecoder:对字符串数据进行解码
  • ObjectDecoder:对Java对象进行解码

存在问题

Netty的对java对象进行解码编码的底层使用的是Java序列化技术,但其效率不高,且无法跨语言,序列化体积是二进制编码5倍多,性能太低

解决方案

可以使用Google的Protobuf,它是一种轻便高效的结构化数据存储格式,用于结构化数据串行化,很适合数据存储或RPC数据交换格式,而且它支持跨语言

常见问题

已经存在NIO,为何还要开发出Netty框架?

  • NIO类库和API繁杂,使用麻烦
  • NIO属于单Ractor单线程模式,需要熟悉掌握线程和网络编程,才可以编写高质量NIO程序
  • 开发工作量和难度大,如面临断连重连、失败缓存、网络拥塞等问题
  • NIO本身存在的Epoll bug,产生空轮询导致CPU爆满

而Netty则解决了如上问题,它基于NIO进行了封装优化,具有如下优点

  • 设计优雅:适用于各种传输类型的统一
  • 高性能、吞吐量更高,延迟更低,减少资源消耗
  • 安全:完整的SSL/TLS支持
  • 社区活跃、版本迭代周期短

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

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

相关文章

开源容灾备份软件,开源cdp备份软件

数据的安全性和完整性面临着硬件问题、黑客攻击、人为错误等各种威胁。在这种环境下,开源容灾备份软件应运而生,通过提供自动数据备份和恢复,有效地保证了公司的数据安全。 一、开源容灾备份软件的定义和作用 开源容灾备份软件是一种基于开源…

SqlServer2019—解决SQL Server 无法连接127.0.0.1的问题

1、打开SQL Server 2019配置管理器 2、SQL Servere 网络配置(启用 Named Pipes 和 TCP/IP) 3、修改TCP/IP协议(右键选择属性—IP地址),具体如下图所示: 4、重启SQL Server服务

漏洞挖掘和漏洞利用技术:讨论漏洞发现、利用和修复,深入研究不同类型漏洞的技术细节

章节一:引言 在当今数字化时代,计算机技术的迅猛发展为我们的生活带来了无数便利,然而也伴随着各种安全威胁。恶意黑客利用漏洞进行攻击已成为一种常见现象。本文将深入探讨漏洞挖掘和漏洞利用技术,以及如何修复这些漏洞&#xf…

智慧充电桩物联网方案架构

智慧充电桩物联网采用“云-管-边-端”的边缘计算物联网架构,融合5G、AI、Wi-Fi 6等技术,实现充电基础设施由数字化向智能化演进。智慧充电桩物联网方案架构设计,如下图所示: 云端: 物联网平台具备广泛协议的南向接入…

基于QCC_BES 平台的LMS自适应滤波算法实现

+我V hezkz17进数字音频系统研究开发交流答疑群(课题组) LMS算法是最小均方(Least Mean Square)算法的缩写。它是一种自适应滤波算法,常用于信号处理、系统辨识和自适应滤波等领域。 LMS算法的目标是通过对输入信号和期望输出信号之间的误差进行最小化,来调整滤波器的权重…

matlab使用教程(22)—非线性优化函数的设置

1.设置优化选项 可以使用由 optimset 函数创建的 options 结构体来指定优化参数。然后,可以将 options 作为输入传递给优化函数,例如,通过使用以下语法调用 fminbnd x fminbnd(fun,x1,x2,options) 或使用以下语法调用 fminsearch x f…

8月21-22日上课内容 第一章 MySQL数据库初始

本章结构 数据库的基本概念 概述(总览) 结构: 数据 表 数据库 数据库管理系统 数据库系统原理 数据 (Data) 描述事物的符号记录 包括数字,文字、图形、图像、声音、档案记录等以“记录”形式按统一的格式进行存储表 将不同…

验证码识别DLL ,滑块识别SDK,OCR图片转文字,机器视觉找物品

验证码识别DLL ,滑块识别SDK 你们用过哪些OCR提取文字,识图DLL,比如Opencv,Labview机器视觉找物品之类?

Selenium的使用:WEB功能测试

Selenium是ThrougthWorks公司一个强大的开源WEB功能测试工具系列,本系统包括多款软件 Selenium语言简单,用(Command,target,value)三种元素组成一个行为,并且有协助录制脚本工具,但Selenese有一些严格的限制: …

FFmpeg解码32k大分辨率出现如下错误:Picture size 32768x32768 is invalid

最近找到一张32k的jpeg图片,尝试用ffmpeg来进行解码,命令如下: ffmpeg -i enflame_32768-32768-420.jpg 32.yuv结果出现Picture size 32768x32768 is invalid的错误: 找到报错的代码文件imgutils.c,以及函数&#x…

Shiro学习总结

第一章 入门概述 1.概念 shiro是一个Java安全框架,可以完成:认证、授权、加密、会话管理、与web集成、缓存… 2.优势 ● 易于使用,构建简单 ● 功能全面 ● 灵活,可以在任何应用程序环境中工作,并且不需要依赖它们…

RabbitMQ笔记-RabbitMQ基本术语

RabbitMQ基本术语 相关概念; 生产者(Producer):投递消息。消息:消息体(payload)标签(label);生产者把消息交给rabbitmq,rabbitmq会根据标签把消息发给感兴趣…

【自动驾驶】TI SK-TDA4VM 开发板上电调试,AI Demo运行

1. 设备清单 TDA4VM Edge AI 入门套件【略】USB 摄像头(任何符合 V4L2 标准的 1MP/2MP 摄像头,例如:罗技 C270/C920/C922)全高清 eDP/HDMI 显示屏最低 16GB 高性能 SD 卡连接到互联网的 100Base-T 以太网电缆【略】UART电缆外部电源或电源附件要求: 标称输出电压:5-20VDC…

第1章:计算机网络体系结构

文章目录 1.1 计算机网络 概述1.概念2.组成3.功能4.分类5.性能指标1.2 计算机网络 体系结构&参考模型1.分层结构2.协议、接口、服务3.ISO/OSI模型4.TCP/IP模型1.1 计算机网络 概述 1.概念 2.组成 1.组成部分&

多线程基础篇(包教包会)

文章目录 一、第一个多线程程序1.Jconsole观察线程2.线程休眠-sleep 二、创建线程三、Thread类及常见方法1. Thread 的常见构造方法2. Thread 的几个常见属性3. 启动线程 - start4. 中断线程5. 等待一个线程 四、线程状态五、线程安全问题(synchronized)(重点&#…

深入理解回调函数qsort:从入门到模拟实现

🍁博客主页:江池俊的博客 💫收录专栏:C语言进阶之路 💡代码仓库:江池俊的代码仓库 🎪我的社区:GeekHub 🎉欢迎大家点赞👍评论📝收藏⭐ 文章目录 前…

七夕学算法

目录 P1031 [NOIP2002 提高组] 均分纸牌 原题链接 : 题面 : 思路 : 代码 : P1036 [NOIP2002 普及组] 选数 原题链接 : 题面 : 思路 : 代码 : P1060 [NOIP2006 普及组] 开心的金明 原题链接 : 题面 : 思路 : 01背包例题 : 代码 : P1100 高低位交换 原题…

HarmonyOS开发第一步,熟知开发工具DevEco Studio

俗话说的好,工欲善其事,必先利其器,走进HarmonyOS第一步,开发工具必须先行,当然了,关于开发工具的使用,官网和其他的博客也有很多的讲解,但是并没有按照常用的功能进行概述&#xff…

诚迈科技子公司智达诚远与Unity中国达成合作,打造智能座舱新时代

2023 年 8 月 23 日,全球领先的实时 3D 引擎 Unity 在华合资公司 Unity 中国举办发布会,正式对外发布 Unity 引擎中国版——团结引擎,并带来专为次世代汽车智能座舱打造的团结引擎车机版。发布会上,诚迈科技副总裁、诚迈科技子公司…

python中的matplotlib画折线图(数据分析与可视化)

先导包(必须安装了numpy 、pandas 和matplotlib才能导包): import numpy as np import pandas as pd import matplotlib.pyplot as plt核心代码: import numpy as np import pandas as pd import matplotlib.pyplot as pltpd.se…