Netty in Action (二十二) 第十一章节 第二部分 Netty提供的一些原生Handler和codecs

11.4 Decoding delimited and length-based protocols

如果你使用Netty工作的时候,你经常会遇到使用分隔符或者指定字节数的方法来解码,接下来的一个小节中将讲解Netty在处理这种问题给出的一些具体实现

11.4.1 Delimited protocols

分隔符协议使用某个固定的字符来标记一个信息或者一个信息端的开头和结尾,被分割的消息块我们称之为“帧”,由RFC文档定义的有很多正式的规范协议,例如SMTP,POP3,IMAP,Telnet,当然,很多私有组织经常也会有他们专有的格式,不管你是使用哪种协议进行工作的,表格11.5列出的一些解码器将会帮助你自定义一些解码器来帮助你可以提取任何分隔符切割的帧数据

图11.5展示了一些帧数据以\r\n为结尾切分的数据如何被分割处理的

下面的代码清单展示了如何使用LineBasedFrameDecoder来实现图11.5展示的问题

如果你使用的帧数据是以某种分隔符切分的,而不是以行为结尾分割切分的话,你可以使用DelimiterBasedFrameDecoder来简化你对这种场景下帧数据的处理,只需要在构造器中指定具体的分割符就可以了

这些解码器是你实现自定义解码器的工具,我们举例说明,我们可以使用如下的场景说明:

1)输入的数据流包含多个数据帧,每一个数据帧以\n为结尾

2)每一个数据帧中包含多个项目,每一个项目将以一个空格符切分

3)每一个帧代表一个命令,这个命令又是有命令的名称和多个参数组成的

我们对于上述的协议规定给出的自定义的解码器簇中给出如下的几个类:

1)Cmd--------在一个ByteBuf中存储一个帧或者一个命令的内容,包括存储该命令的名称和参数

2)CmdDecoder-----------通过覆盖decode方法来检索一行数据,从这行数据中构造一个或者多个Cmd的实例

3)CmdHandler------------从CmdDecoder中获取Cmd对象,并对此对象做一些操作

4)CmdHandlerInitializer----------------为了方便,我们将先前定义的一些类通过专门的ChannelInitializer嵌入到管道的handler链中去

完整的代码清单如11.9所示,这个解码器的核心是实现了LineBasedFrameDecoder

11.4.2 Length-based protocols

一个基于长度的规范定义了一个帧数据在这个帧数据的头部编译了这个帧数据的长度,而不是用某些指定的字符去切分字符,表11.6展示了Netty提供的2中解码器来处理这种类型的规范协议

图11.6展示了固定帧大小的FixedLengthFrameDecoder的解码器如何处理8字节的帧数据的

你经常遇到一种场景,帧数据的大小并不是一个固定的,为了处理这种数据帧的大小是变量的问题我们可以使用LengthFieldBasedFrameDecoder,这个类可以从每个帧数据的头部信息知道帧数据的大小,然后从数据流中获取对应大小的帧数据

图11.7展示了一个例子,这个例子中帧数据头部的长度占用了2个字节,下标从0开始,长度有2个字节

LengthFieldBasedFrameDecoder提供了多个构造器来覆盖帧数据头部数据多变的场景,代码清单11.10使用了一个构造器,这个构造器的三个入参是maxFrameLength,lengthFieldOffset和LengthFieldLength,在这个使用案例中,每个帧的长度是在帧的前八个字节中定义的

截止到目前为止,你已经学习过Netty提供的几个译码器,这几个译码器用来支持多种数据帧的结构,这些数据帧的结构规范包括如下几种,一是以某种字符分割切分而形成的数据帧,而是固定长度的数据帧,三是变长的数据帧,该数据帧的长度会在该帧的头部指定,随着更多协议和规范的形成然你会发现和编写更多各种各样的译码器,并且将这些译码器进行归类和分档,形成一个更加完整的体系

11.5 Writing big data

如何在异步框架中高效地写入大数据块会因为网络饱和的可能性成为一个很特别的问题,因为写的操作是不会阻塞的,他们甚至会在所有的数据并没有完全写入的时候返回完成状态并且通知ChannelFuture,当这种情况发生的时候,你将会冒着内存溢出的风险不停的写入且写入的操作无法被终止,所以当你写入大数据块的时候,你需要做好准备处理这样的案例:当慢速连接到一个远程端的时候会产生释放内存的延迟,我们举一个例子写入一个文件到网络中

在我们之前4.2章节讨论的传输协议上我们提及过NIO的零拷贝的特性,这个特性会消除拷贝过程,当需要将文件系统中的一个文件移动网络中的时候,这些过程将会在Netty的核心模块发生,所以在做这个实践的时候,应用需要给出接口FileRegion的一个具体实现,这个接口在Netty的文档中是这样定义的:某个文件的区域需要通过Channel发送这块区域需要支持零拷贝传输

下面的代码清单中展示了你如何在使用零拷贝的技术传输一个文件内容的,从FileInputStream中创建一个DefaultFileRegion,且将其写入到Channel中

这个例子中只能应用直接的文件内容传输,系统不能有对该文件的任何操作,如果有对该文件的操作需要你把数据从文件系统中拷贝到用户内存里来,你可以使用ChunkedWriteHandler,它支持在没有高内存损耗的情况下异步地写入大的数据流

做到这个功能的核心就是接口ChunkedInput<B>,这里的B指的是方法readChunk方法返回的类型,这个接口给出了四个实现,如下列表11.7所示,每一个都代表了被ChunkedWriteHandler消费的一个没有限定长度的数据流

代码清单11.12说明了ChunkedStream的使用,这种类型的实现经常使用在实际场景中,这个类也展示了文件和SslContext的初始化,当initChannel方法调用的时候,它初始化了包涵链式处理器的Channel

当channel的状态被激活的时候,WriteStreamHandler将会把文件块当做一个ChunkedStream写入,在文件传输之前会使用SslHandler进行加密

块状输入:使用你自己ChunkedInput的实现在管道中安装一个ChunkedWriteHandler

在这个小节中,我们讲解了如何使用零拷贝这种特性来高效地传输,如何不冒着OOM的风险传输大数据------使用ChunkedWriteHandler,在下一个小节中,我们将介绍几种序列化POJOs的几种方式

11.6 Serializing data

JDK提供了ObjectOutputStream和ObjectInputStream用来序列化和反序列化原生的数据类型和POJO用来网络传输,这系列的API并不是很复杂,可以应用到任何实现java.io.Serializable接口的对象,但是这并不是非常高效的方法,在这个小节中,我们将了解Netty对序列化提供的一些工具类

11.6.1 JDK serialization

如果你的应用使用ObjectOutputStream和ObjectInputStream来与远程端进行交互的时候,兼容性的问题是你最主要担心的问题,JDK的序列化将是你解决这类问题的最好方法,表11.8展示了Netty提供的一些基于JDK的一些序列化的类的介绍

11.6.2 Serialization
with JBoss Marshalling

如果你可以自由选择使用一些其他的依赖,那么JBoss的Marshalling将是一个不错的选择,它将比JDK的序列化的速度快3倍且序列化的内容显得更加紧凑

Netty提供了对JBoss的Marshalling的支持,以解码器和编码器的形式支持,如表11.9所示,第一块是以JDK的序列化的实现做到了兼容性的支持,第二种是在保证兼容性的同时,提供了最大的性能,它底层是使用JBoss的Marshalling实现的

下面的代码清单再次向你展示了如何使用MarshallingDecoder和MarshallingEncoder,这几乎只需要正确的配置ChannelPipeline就可以了

11.6.3
Serialization via Protocol Buffers

Netty对序列化的最后一个解决方案是使用Protocol Buffers的一个译码器,这个ProtoBuf是由Google开发用户进行数据交互的,现在已经开源了,源代码可以在https://github.com/google/protobuf网站上找到

ProtoBuf对结构化的数据以更加紧凑更加高效地方式进行编码和解码,它现在已经被多种语言进行了实现,使其能够进行更好地应用于跨语言的项目,表11.10展示了Netty对ProtoBuf支持而提供的ChannelHandler的实现

在这里,我们再一次只需要将恰当的ChannelHandler增加到ChannelPipeline中去,如下面代码清单11.14所示:

在这个小节中,我们介绍了Netty提供的几种序列化方式,这几种序列化方式是通过编码和解码的形式给出的,且这几种序列化方法是基于如下几种具体的实现的1)JDK的序列化方式,JBoss的Marshalling和Google的ProtoBuf

11.7 Summary

由Netty原生提供的几个译码器和处理器可以联合使用,用来处理各式各样的业务场景,并且这些组件已经在很多大型的业务项目的使用过程中被证明是稳健的

请注意,在我们本章节的介绍过程中,我们只是对非常常用的API给出了最常用的使用方式,更多详细且精细的API请参考API文档

在下一个章节中,我们将学习另一个比较先进的协议用来提高web开发的性能的协议WebSocket,Netty对WebSocket提供了很多工具,利用这些工具你可以很方便地使用WebSocket

时间: 2024-10-08 14:57:54

Netty in Action (二十二) 第十一章节 第二部分 Netty提供的一些原生Handler和codecs的相关文章

Netty in Action (二十一) 第十一章节 第一部分 Netty提供的一些原生Handler和codecs

本章内容包括(分2次翻译): 1)利用SSL/TLS构建安全的Netty应用 2)构建HTTP/HTTPS的应用 3)处理闲置的连接和超时 4)空格符切分协议和长度切分的协议的解码 5)写入大数据 Netty为各式各样的协议提供了很多译码器和处理器的类,这些类你可以做到拿来即用,可以使你在有些比较麻烦的事件上不用花费不必要的时间和精力,在这个章节我们将会把这些工具介绍给你,且一一分析他们的作用,这些工具包括:支持SSL/TLS和Websocket的工具,也有比HTTP天然的数据压缩更高性能的数据

Netty in Action (十二) 第五章节 第一部分 简介ByteBuf

第五章 ByteBuf(分四部分翻译) 本章节包括: 1)ByteBuf------Netty的数据容器 2)API介绍 3)使用案例 4)内存分配 我们之前提到过很多次,网络传输数据的最基本的数据单元是byte,Java的NIO提供了ByteBuffer作为字节的容器,但是这个类的使用有些过于复杂和麻烦 Netty对ByteBuffer提供了一个可选方案ByteBuf,一个很好的解决方案,解决了JDK原生的ByteBuffer的API使用不易的问题,同时ByteBuf为应用程序开发者提供了一系

Netty in Action (十九) 第九章节 单元测试

本章内容包括: 1)单元测试 2)EmbeddedChannel的说明 3)使用EmbeddedChannel测试ChannelHandler 对于一个Netty应用来说,ChannelHandler是一个至关重要的元素,所以充分地去测试ChannelHandler应该是你开发过程中必要的组成部分,我们的最佳实践会告诉你测试不仅能保证你的具体实现的正确性,更重要的是,当你突然变更你的代码的时候,它能很容易地去隔离问题,这种类型的测试叫做单元测试 尽管对单元测试大家没有一个完整的定义,但是更多的参

Netty in Action (十三) 第五章节 第二部分 ByteBuf字节层面的操作

5.3 Byte-level operations ByteBuf除了提供基本对数据读写操作之外,它还提供了很多其他的方法,在接下来的这个小节中,我们将讨论这些方法中比较重要的来分析讲解一下 5.3.1 Random access indexing 与正常的java的字节数组一样,ByteBuf的索引下标也是从0开始的,第一个索引下表是0,最后一个字节索引总是它的容量-1,下面的代码清单向你展示了ByteBuf封装了它的存储机制,可以使我们很方便地去迭代ByteBuf中的内容 注意到如果想获取B

【管理心得之二十二】小人物 仰视 大授权

场景再现====================Boss:小王,来我办公室一下.小王: 嗯Boss:近期总公司有会,需要到外地出差几日.我不在的这段期间里,公司大小事务你帮忙处理一下.          如果有什么难决定的事,第一时间电话.邮件联系我商定即可.小王:  明白.放心吧领导,绝不会让你失望的Boss:嗯,那就好,没事了. {小王走出办公室} 心中暗喜,"难道这就是传说中的授权,Boss不在的时候,我岂不是最高权力的行使者." ==================== 从场景

QT开发(二十二)——QMainWindow主窗口

QT开发(二十二)--QMainWindow主窗口 一.主窗口简介 应用程序中的主窗口是与用户进行长时间交互的顶层窗口,提供了应用程序的大部分功能,通常是应用程序启动后的第一个窗口,应用程序一般由一个主窗口和多个对话框组成. QT中直接支持主窗口,QMainWindow是QT中主窗口的基类,是继承于QWidget类的容器型组件. QMainWindow内部封装了菜单栏.工具栏.中心组件.停靠组件.状态栏等. QMainWindow内置了布局管理器,基本的组件布局如下: 二.菜单栏 QT中提供了预

Bootstrap &lt;基础二十二&gt;超大屏幕(Jumbotron)

Bootstrap 支持的另一个特性,超大屏幕(Jumbotron).顾名思义该组件可以增加标题的大小,并为登陆页面内容添加更多的外边距(margin).使用超大屏幕(Jumbotron)的步骤如下: 创建一个带有 class .jumbotron. 的容器 <div>. 除了更大的 <h1>,字体粗细 font-weight 被减为 200px. 下面的实例演示了这点: <!DOCTYPE html> <html> <head> <tit

华为上机题汇总(二十二)

华为上机题汇总(二十二) 注:编译环境为Visual Studio 2012,答案仅供参考. 目录 华为上机题汇总二十二 目录 第一百零六题 第一百零七题 第一百零八题 第一百零九题 第一百一十题 第一百一十一题 第一百零六题 106.去饭店吃饭 一个男人3元 一个女人2元 一个小孩1元 现输入总人数和总花费 #include <iostream> #include <vector> using namespace std; void display(const vector<

《Programming in Lua 3》读书笔记(二十二)

日期:2014.8.6 PartⅣ The C API 26 Extending Your Application 使用Lua很重要的一点是用来做配置语言.配合主语言做一些功能的配置. 26.1 The Basics 有的时候程序需要配置一些功能信息,很多时候可能有许多别的方法比用lua做配置要更简单:如使用环境变量或者读取文件,读取文件涉及到文件的解析.如果使用Lua进行配置的话,相当于用lua文件替代了要读取的如csv.txt文件等. 使用Lua进行配置的时候,就需要使用Lua API去控制