一起学netty(13)编码器和解码器概念理解

weblog 65 0 0

编码器和解码器

在网络应用中需要实现某种编解码器,将原始字节数据与自定义的消息对象进行互相转换。网络中都是以字节码的数据形式来传输数据的,服务器编码数据后发送到客户端,客户端需要对数据进行解码。

netty提供了强大的编解码器框架,使得我们编写自定义的编解码器很容易,也容易封装重用。对于Netty而言,编解码器由两部分组成:编码器、解码器。  

  • 解码器:负责将消息从字节或其他序列形式转成指定的消息对象。
  • 编码器:将消息对象转成字节或其他序列形式在网络上传输。

Netty 的编(解)码器实现了 ChannelHandlerAdapter,也是一种特殊的 ChannelHandler,所以依赖于 ChannelPipeline,可以将多个编(解)码器链接在一起,以实现复杂的转换逻辑。

Netty里面的编解码:  

  • 解码器:负责处理“入站 InboundHandler”数据。    
  • 编码器:负责“出站 OutboundHandler” 数据。

解码器(Decoder)

解码器负责 解码“入站”数据从一种格式到另一种格式,解码器处理入站数据是抽象ChannelInboundHandler的实现,所以解码器的本质还是入栈处理器,只不过解码器又对解码器做了进一步的抽象。实践中使用解码器很简单,就是将入站数据转换格式后传递到ChannelPipeline中的下一个ChannelInboundHandler进行处理;这样的处理时很灵活的,我们可以将解码器放在ChannelPipeline中,重用逻辑。

对于解码器,Netty中主要提供了抽象基类ByteToMessageDecoder和MessageToMessageDecoder。

  1. ByteToMessageDecoder: 用于将字节转为消息,需要检查缓冲区是否有足够的字节。
  2. ReplayingDecoder: 继承ByteToMessageDecoder,不需要检查缓冲区是否有足够的字节,但是 ReplayingDecoder速度略慢于ByteToMessageDecoder,同时不是所有的ByteBuf都支持。
  3. MessageToMessageDecoder: 用于从一种消息解码为另外一种消息(例如POJO到POJO)。

ByteToMessageDecoder解码器

用于将接收到的二进制数据(Byte)解码,得到完整的请求报文(Message),ByteToMessageDecoder继承自ChannelInboundHandlerAdapter,是一种入栈处理器,可以称为解码器,负责将byte字节流(ByteBuf)转换成自己定义的Message数据类型。

抽象方法:

protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)

这个方法是唯一的一个需要自己实现的抽象方法,作用是将ByteBuf数据解码成其他形式的数据。

参数:

  • ctx:ChannelHandler上下文
  • In:需要进行解码的二进制字节数组
  • out:该容器内的对象要传递给下一个解码器或者下一个入栈处理器。也就是将解码后的对象放入该容器。

ByteToMessageDecoder提供的一些常见的实现类:

  • FixedLengthFrameDecoder:定长协议解码器,我们可以指定固定的字节数算一个完整的报文
  • LineBasedFrameDecoder:  行分隔符解码器,遇到\n或者\r\n,则认为是一个完整的报文
  • DelimiterBasedFrameDecoder:    分隔符解码器,与LineBasedFrameDecoder类似,只不过分隔符可以自己指定
  • LengthFieldBasedFrameDecoder:长度编码解码器,将报文划分为报文头/报文体,根据报文头中的Length字段确定报文体的长度,因此报文提的长度是可变的
  • JsonObjectDecoder:json格式解码器,当检测到匹配数量的"{" 、”}”或”[””]”时,则认为是一个完整的json对象或者json数组。

由于ByteToMessageDecoder解码器实现相对比较复杂,我们下一章将对其单独重点分析。本章主要是理解编码器和解码器的概念。

MessageToMessageDecoder

ByteToMessageDecoder是将二进制流进行解码后,得到有效报文。而MessageToMessageDecoder则是将一个本身就包含完整报文信息的对象转换成另一个Java对象。所以相比于ByteToMessageDecoder要直接处理二进制字节而言MessageToMessageDecoder相对就比较简单。《一起学netty(5)netty入门程序案例》一文中提到的StringDecoder就是MessageToMessageDecoder的实现类。

编码器(Encoder)

ByteToMessageDecoderMessageToMessageDecoder相对应,Netty提供了对应的编码器实现MessageToByteEncoder和MessageToMessageEncoder,二者都实现了ChannelOutboundHandler接口,所以它们也就是出栈处理器。

相对来说,编码器比解码器的实现要更加简单,原因在于解码器除了要按照协议解析数据,还要要处理粘包、拆包问题;而编码器只要将数据转换成协议规定的二进制格式发送即可。

MessageToByteEncoder

MessageToByteEncoder也是一个泛型类,泛型参数表示将需要编码的对象的类型,编码的结果是将信息转换成二进制流放入ByteBuf中。子类通过覆写其抽象方法encode来实现编码。

protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception;

MessageToMessageEncoder

MessageToMessageEncoder同样是一个泛型类,泛型参数表示将需要编码的对象的类型,编码的结果是将信息放到一个List中。子类通过覆写其抽象方法encode,来实现编码。

public abstract class MessageToMessageEncoder<I> extends ChannelOutboundHandlerAdapter {

  ...

  protected abstract void encode(ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception;

  ...

}

与MessageToByteEncoder不同的,MessageToMessageEncoder编码后的结果放到的out参数类型是一个List中。例如,你一次发送2个报文,因此msg参数中实际上包含了2个报文,因此应该解码出两个报文对象放到List中。

MessageToMessageEncoder提供的常见子类包括:

  • LineEncoder:按行编码,给定一个CharSequence(如String),在其之后添加换行符\n或者\r\n,并封装到ByteBuf进行输出,与LineBasedFrameDecoder相对应。
  • Base64Encoder:给定一个ByteBuf,得到对其包含的二进制数据进行Base64编码后的新的ByteBuf进行输出,与Base64Decoder相对应。
  • LengthFieldPrepender:给定一个ByteBuf,为其添加报文头Length字段,得到一个新的ByteBuf进行输出。Length字段表示报文长度,与LengthFieldBasedFrameDecoder相对应。
  • StringEncoder:给定一个CharSequence(如:StringBuilder、StringBuffer、String等),将其转换成ByteBuf进行输出,与StringDecoder对应。这些MessageToMessageEncoder实现类最终输出的都是ByteBuf,因为最终在网络上传输的都要是二进制数据。
猜你喜欢
official 61 个Pipeline。入栈处通常是ChannelInboundHandlerAdapter的子类,主要用于读取客户端的数据。(包括数据包,业务逻辑处等)出栈处通常是ChannelO
official 72 篇《netty(2)nio模型及多路复用》中已经简单介绍了nio模型,以及多路复用,并了nio是非阻塞的网络模型,以及与bio的区别。本篇将继续深入nio,以及select
official 110 高了效率。本文我们继续探究EventLoop、EventLoopGroup的以及nio代之间的关系。EventLoopEventLoop是个事件循环对象,本质上是个单线程的执行(其中维护了
official 54 之前的文章中提到了java中的nio是同步非阻塞的网络io模型,本文就主要说明下同步、异步、阻塞、非阻塞的来帮助nio。io操作IO分两阶段(旦拿到数据后就变成了数据操作,不再是IO
official 23 什么是心跳?顾名思义,所谓心跳,即在TCP长连接中,客户端服务之间定期发送的种特殊的数据包,通知对方自己还在线,以确保TCP连接的有效性。为什么需要心跳?因为网络的不可靠性,有可能在TCP保持
java基础 933 与补.机真值在习原,反之前,需要先了真值的.1、机个数在计算机中的二进制表示形式,叫做这个数的机数。机数是带符号的,在计算机用个数的最高位存放
official 41 ChannelInboundHandlerChannelInboundHandler是入栈消息处的核心接口,如下
java虚拟机(jvm) 4132 常是按需加载,即第次使用该类时才加载。由于有了类加载,Java运行时系统不需要知道文件与文件系统。习类加载时,掌握Java的委派很重要。1.类的加载过程:2.类的生命周期:加载:"加载"是"
目录
祝愿神州十三飞行乘组平安归来