Netty 3 - 组件和设计

这里将回顾我们之前章节讲到过的主要概念和组件。

1 Channel 、EventLoop和ChannelFuture

  • Channel —— Socket;
  • EventLoop —— 控制流、多线程处理、并发;
  • ChannelFuture —— 异步通知。

1.1 Channel 接口

基本的I/O操作(bind()、connect()、read()和write())依赖于底层网络传输所提供的原语。在基于Java的网络编程中,其基本的构造是Class Socket。Netty的Channel接口所提供的API,大大降低了直接使用Socket类的复杂性。此外,Channel也是拥有许多预定义的、专门化实现的广泛类层次结构的根,下面是一个简短的部分清单:

  • EmbeddedChannel
  • LocalServerChannel
  • NioDatagramChannel
  • NioSctpChannel
  • NioSockectChannel

1.2 EventLoop接口

EventLoop定义了Netty的核心抽象,用于处理连接的声明周期中所发生的事件。下图在高层次上说明Channel、EventLoop、Thread以及EventLoopGroup之间的关系。

  • 一个EventLoopGroup包含一个或者多个EventLoop
  • 一个EventLoop在它的生命周期内只和一个Thread绑定
  • 所有由EventLoop处理的I/O事件都将在它专有的Thread上被处理
  • 一个Channel在它的生命周期内只注册于一个EventLoop
  • 一个EventLoop可能会被分配给一个或多个Channel

注意,在这种设计中,一个给定Channel的I/O操作都是由相同的Thread执行的,实际上消除了对于同步的需要。

1.3 ChannelFuture接口

Netty中所有的I/O操作都是异步的。因为一个操作可能不会立即返回,所以我们需要一种用于在之后的某个时间点确定其结果的方法。为此,Netty提供了ChannelFuture接口,其addListener()方法注册了一个ChannelFutureListener,以便于在某个操作完成时(无论是否成功)得到通知。

可以将ChannelFuture看作将来要执行的操作的结果的占位符。它究竟什么时候被执行则可能取决于若干的因素,因此不可能准确地预测,但是可以肯定的是它将会被执行。此外,所有属于同一个Channel的操作都被保证其将它们被调用的顺序执行。

2 ChannelHandler 和 channelPipeline

我们将更加细致地看一看那些管理数据流以及执行应用程序处理逻辑的组件。

2.1 ChannelHandler接口

从应用程序开发人员的角度来看,Netty的主要组件是ChannelHandler,它充当了所有处理入站和出站数据的应用程序逻辑的容器。实际上,ChannelHandler可专门用于几乎任何类型的动作,如将数据从一种格式转换为另一种格式,或处理转换过程中排除的异常。

其中,ChannelInboundHandler是开发人员经常实现的子接口,可以接收入站事件和数据。这些数据在随后将会被应用程序的业务逻辑所处理。

2.2 ChannelPipeline接口

ChannelPipeline提供了ChannelHandler链的容器,并定义了用于在该链上传播入站和出站事件流的API。当Channel被创建时,它会被自动地分配到它专属的ChannelPipeline。

ChannelHandler安装到ChannelPipeline中的过程如下所示:

  • 一个ChannelInitalizer的实现被注册到了ServerBootstrap中;
  • 当ChannelInitalizer.initChanel()方法被调用时,ChannelInitalizer将在ChannelPipeline中安装一组自定义的ChannelHandler;
  • ChannelInitializer将它自己从ChannelPipeline中移除

ChannelHandler是专为支持广泛的用途而设计的,可以将它看作处理往来ChannelPipeline事件(包括数据)的任何代码的通用容器。类图如下所示:

ChannelPipeline是ChannelHandler的编排顺序。下图将说明Netty应用程序中入站和出站数据流之间的区别。从客户端角度看,如果事件的运动方向是从客户端到服务端,那么我们称这些事件为出站,反之则为入站。

上图显示了入站和出站的ChannelHandler可以被安装到同一个ChannelPipeline中。如果一个小希或者任何其他的入站事件被读取,那么它会从ChannelPipeline的头部开始流动,并被传递给第一个ChannelInboundHandler。这个ChannelHandler不一定会实际地修改数据,具体取决于它的具体功能,在这之后,数据将会被传递给链中的下一个ChannelInboundHandler。最终,数据将会到达ChannelPipeline的尾端。届时,所有处理就都结束了。

数据的出站运动(即正在被写的数据)的概念上也是一样的。在这种情况下,数据将从ChannelOutboundHandler链的尾端开始流动,直到它到达链的头部位置。在这之后,出站数据将会到达网络传输层,这里显示为Socket。通常情况下,这将触发一个写操作。 

关于入站和出站channelHandler的更多讨论

通过使用作为参数传递到每一个方法的ChannelHandlerContext,事件可以被传递给当前ChannelHandler链中的下一代ChannelHandler。因为你有时候会忽略那些不感兴趣的事件,所以Netty提供了抽象基类ChannelInboundHandlerAdapter和ChannelOutHandlerAdapter。通过调用ChannelHandlerContext上的对应方法,每个都提供了简单地将事件传递给下一个ChannelHandler的方法实现。随后,你可以通过重写你感兴趣的那些方法来扩展这些类。

鉴于出站操作和入站操作是不同的,如果两个类别的ChannelHandler都混合添加到同一个ChannelPipeline中会发生什么?虽然ChannelInboundHandler和ChannelOutboundHandler都扩展自ChannelHandler,但是Netty能区分ChannelInboundHandler实现和ChannelOutboundHandler实现,并确保数据只会在具有相同定向类型的两个ChannelHandler之间传递。

当ChannelHandler被添加到ChannelPipeline时,它将会被分配一个ChannelHandlerContext,其代表了ChannelHandler和ChannelPipeline之间的绑定。虽然这个对象可以被用于获取底层的Channel,但是它主要还是被用于写出站数据。 

在Netty中,有两种发送消息的方式。

  1. 直接写到Channel中,导致信息从ChannelPipeline的尾端开始流动。
  2. 写到和ChannelHandler相关联的ChannelHandlerContext对象中,导致消息从ChannelPipeline中的下一个ChannelHandler开始流动。

2.3 更加深入地了解ChannelHandler

ChannelPipeline中的每个ChannelHandler将负责把事件转发到链中的下一个ChannelHandler.这些适配器类(及它们的子类)将自动执行这个操作,所以你可以只重写那些你想要特殊处理的方法和事件。

为什么需要适配器类

有一些适配器类可以编写自定义的ChannelHandler所需要的努力降到最低限度,因为他们提供了定义在对应接口中的所有方法的默认实现。

下面这些是编写自定义ChannelHandler时经常会用到的适配器类:

  • ChannelHandlerAdapter
  • ChannelInboundHandlerAdapter
  • ChannelOutboundHandlerAdapter
  • ChannelDuplexHandler

我们将研究3个ChannelHandler的子类型:编码器、解码器和SimpleChannelInboundHandler<T>-ChannelInboundHandlerAdapter的一个子类。

2.4 编码器和解码器

 当程序员通过Netty发送或者接收一个消息的时候,就将会发生一次数据转换。入站消息会被解码。也就是说,从字节转换为另一种格式,通常是一个Java对象。如果是出站消息,则会发生相反方向的转换:它将从它的当前格式被编码为字节。

这两种方向的转换原因,即网络数据总是一系列的字节。

对应于特定的需求, Netty为编码器和解码器提供了不同类型的抽象类。如,你的应用程序可能使用了一个中间格式,而不需要立即将消息转换成字节。你将仍然需要一个编码器,但是它将派生自一个不同的超类。为了确定合适的编码器类型,你可以应用一个简单的命名约定。

通常来说,这些基类的名称类似于ByteToMessageDecoder或MessageToByteEncoder。对于特殊的类型,你可能会发现类似于ProtobufEncoder和ProtobufDecoder这样的名称——预置的用来支持Google的Protocol Buffers。

严格说来,其他的处理器也能够完成编码器和解码器的功能,即Netty提供的编码器/解码器适配器类都实现了ChannelOutboundHandler或ChannelInboundHandler接口。

2.5 抽象类SimpleChannelInboundHandler

当我们要创建一个ChannelHandler来接收解码消息时,可以扩展基类SimpleChannelInboundHandler<T>,其中T是要处理的消息的Java类型。在这个ChannelHandler中将需要重写基类的一个或者多个方法,并且获取一个到ChannelHandlerContext的引用,这个引用将作为输入参数传递给ChannelHandler的所有方法。

基于SimpleChannelInboundHandler实现的Handler,最重要的方法是 channelRead0(ChannelHandlerContext,T)。除了要求不阻塞当前的I/O线程之外,其具体实现完全取决于开发者。

3 引导

Netty的引导类为应用程序的网络层配置提供了容器,这涉及将一个进程绑定到某个指定的端口(引导一个服务器),或者将一个进程连接到另一个运行在某个指定主机的指定端口上的进程(引导一个客户端)。

面向连接的协议:严格来说,“连接”这个术语仅适用于面向连接的协议,如TCP,其保证了两个连接端点之间消息的有序传递。

因此有两种类型的引导,Bootstrap可用于引导客户端,ServerBootstrap可用于引导服务器。如下所示,比较了这两种类型的引导类。

类别BootstrapServerBootstrap
网络编程中的作用连接到远程主机和端口绑定到一个本地端口
EventLoopGroup的数目12

ServerBootstrap绑定到了一个端口,因此服务器必须要监听连接,而Bootstrap则是由想要连接到远程节点的客户端应用程序所使用。引导一个客户端只需要一个EventLoopGroup,但ServerBootStrap则需要两个。

为啥服务端需要两个EventLoopGroup?

是因为服务端需要两组不同的channel。第一组将只包含一个ServerChannel,代表服务器自身的已绑定到某个本地端口的正在监听的套接字。而第二组将包含所有已创建的用来处理传入客户端连接的channel。以下图将说明服务端为啥需要两个不同的EventLoopGroup。

4 总结

这里我们从技术和体系结构两个角度探讨了Netty的重要性,也更加详细地介绍了一些概念和组件,特别是对ChannelHandler、ChannelPipeline和引导等概念做了阐述。

另外,我们讨论了ChannelHandler类的层次结构,对编码器/解码器做了介绍,并描述了他们在数据和网络字节格式之间来回转换的互补功能。

后面的文章将更深入介绍这些组件,并剖析原理。

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

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

相关文章

免注册,ChatGPT可即时访问了!

AI又有啥进展&#xff1f;一起看看吧 Apple进军个人家用机器人 Apple在放弃自动驾驶汽车项目并推出混合现实头显后&#xff0c;正在进军个人机器人领域&#xff0c;处于开发家用环境机器人的早期阶段 报告中提到了两种可能的机器人设计。一种是移动机器人&#xff0c;可以跟…

鸿蒙OS元服务开发:【(Stage模型)学习窗口沉浸式能力】

一、体验窗口沉浸式能力说明 在看视频、玩游戏等场景下&#xff0c;用户往往希望隐藏状态栏、导航栏等不必要的系统窗口&#xff0c;从而获得更佳的沉浸式体验。此时可以借助窗口沉浸式能力&#xff08;窗口沉浸式能力都是针对应用主窗口而言的&#xff09;&#xff0c;达到预…

二叉堆解读

在数据结构和算法中&#xff0c;二叉堆是一种非常重要的数据结构&#xff0c;它被广泛用于实现优先队列、堆排序等场景。本文将介绍二叉堆的基本概念、性质、操作以及应用场景。 一、基本概念 二叉堆是一种特殊的完全二叉树&#xff0c;它满足堆性质&#xff1a;对于每个节点…

电子商务平台中大数据的应用|主流电商平台大数据采集API接口

(一)电商平台物流管理中大数据的应用 电商平台订单详情订单列表物流信息API接口应用 电子商务企业对射频识别设备、条形码扫描设备、全球定位系统及销售网站、交通、库存等管理软件数据进行实时或近实时的分析研究,提高物流速度和准确性。部分电商平台已建立高效的物流配送网…

【STL】vector的底层原理及其实现

vector的介绍 vector是一个可变的数组序列容器。 1.vector的底层实际上就是一个数组。因此vector也可以采用连续存储空间来存储元素。也可以直接用下标访问vector的元素。我们完全可以把它就当成一个自定义类型的数组使用。 2.除了可以直接用下标访问元素&#xff0c;vector还…

掌握数据相关性新利器:基于R、Python的Copula变量相关性分析及AI大模型应用探索

在工程、水文和金融等各学科的研究中&#xff0c;总是会遇到很多变量&#xff0c;研究这些相互纠缠的变量间的相关关系是各学科的研究的重点。虽然皮尔逊相关、秩相关等相关系数提供了变量间相关关系的粗略结果&#xff0c;但这些系数都存在着无法克服的困难。例如&#xff0c;…

解决win7作为虚拟机无法复制粘贴共享文件的问题

win7作为虚拟机经常会出现无法与主机的剪切板共享、文件共享。 归根结底是win7虚拟机里面没有安装VMware Tools 能够成功安装vmware tools的条件&#xff1a; 1&#xff09;win7版本为win7 sp1及以上 2&#xff09;安装KB4490628&#xff0c;KB4474419补丁 因此下面来详细介绍…

【LeetCode题解】2192. 有向无环图中一个节点的所有祖先+1026. 节点与其祖先之间的最大差值

文章目录 [2192. 有向无环图中一个节点的所有祖先](https://leetcode.cn/problems/all-ancestors-of-a-node-in-a-directed-acyclic-graph/)思路&#xff1a;BFS记忆化搜索代码&#xff1a; 思路&#xff1a;逆向DFS代码&#xff1a; [1026. 节点与其祖先之间的最大差值](https…

为什么说AI的尽头是生物制药?

AI的尽头究竟是什么&#xff1f;有投资者说是光伏&#xff0c;也有投资者说是电力&#xff0c;而英伟达给出的答案则是生物制药。 在英伟达2023年投资版图中&#xff0c;除AI产业根基算法与基础建设外&#xff0c;生物制药是其重点布局的核心赛道。英伟达医疗保健副总裁Kimber…

FastEI论文阅读

前言 研究FastEI&#xff08;Ultra-fast and accurate electron ionization mass spectrum matching for compound identification with million-scale in-silico library&#xff09;有很长时间了&#xff0c;现在来总结一下&#xff0c;梳理一下认知。PS&#xff1a;为什么要…

【LeetCode: 21. 合并两个有序链表 + 链表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

axios快速入门

一、环境配置 1.1概述 上古浏览器页面在向服务器请求数据时&#xff0c;因为返回的是整个页面的数据&#xff0c;页面都会强制刷新一下&#xff0c;这对于用户来讲并不是很友好。并且我们只是需要修改页面的部分数据&#xff0c;但是从服务器端发送的却是整个页面的数据&#…

攻防世界 Broadcast 题目解析

Broadcast 一&#xff1a;题目 二&#xff1a;解析 将压缩包解压&#xff0c;得到如上图所示&#xff0c;打开task.py&#xff0c;之后得到flag 这个有点简单了&#xff0c;不要被解压后文件太多所迷惑。

InnoDB中的索引方案

文章目录 InnoDB中的索引方案 InnoDB支持多种类型的索引&#xff0c;包括B-tree索引、全文索引、哈希索引等。B-tree索引是InnoDB存储引擎的默认索引类型&#xff0c;适用于所有的数据类型&#xff0c;包括字符串、数字和日期等。 以下是创建InnoDB表及其B-tree索引的示例代码…

VBA数据库解决方案第九讲:把数据库的内容在工作表中显示

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…

2024年阿里云4核8G服务器多少钱一年?4C8G服务器955元

阿里云服务器4核8G租用优惠价格955元一年&#xff0c;配置为云服务器ECS通用算力型u1实例4核8G配置、ESSD Entry盘20G-40G、1M-3M带宽&#xff0c;实例规格为ecs.u1-c1m2.xlarge&#xff0c;阿里云优惠活动 yunfuwuqiba.com/go/aliyun 活动链接打开如下图&#xff1a; 阿里云4核…

【数据结构】ArrayList详解

目录 前言 1. 线性表 2. 顺序表 3. ArrayList的介绍和使用 3.1 语法格式 3.2 添加元素 3.3 删除元素 3.4 截取部分arrayList 3.5 其他方法 4. ArrayList的遍历 5.ArrayList的扩容机制 6. ArrayList的优缺点 结语 前言 在集合框架中&#xff0c;ArrayList就是一个…

spring boot学习第十六篇:配置多数据源

1、代码参考&#xff1a; dynamic-ds/spring-boot-dynamic-ds at main veminhe/dynamic-ds GitHub 2、验证 2.1调用POST接口http://localhost:8081/hmblogs/blog/addBlog 2.2改动数据源为BJ 然后调用接口添加数据 然后查看ds0库的博客数据

【最新可用】Claude国内镜像,可上传图片,可用Claude3全系模型(包括Pro版本的Opus)!亲测比GPT好用!

亲测可用&#xff0c;镜像地址&#xff1a;Claude 3 镜像 使用方法 访问镜像&#xff1a;Claude 3 镜像 2. 点击设置&#xff0c;配置授权码&#xff0c;关闭设置。这里免费赠送一个体验版的授权码 sk-SZcJyvx3RXRID624E2D3795578Df44C7Af03F2909a8f5eA0 即可发起对话啦&…

Android Studio学习9——使用Logcat打印日志

在Android开发中&#xff0c;Logcat是一个工具&#xff0c;它允许开发者查看设备或模拟器的日志信息。开发者可以使用Log类来打印日志信息&#xff0c;这对于调试和错误排查非常有帮助。 v 或 verbose: 最低等级&#xff0c;显示所有消息。d 或 debug: 用于调试消息。i 或 info…