文档章节

netty的编解码器介绍

刺猬一号
 刺猬一号
发布于 2017/05/24 20:30
字数 1559
阅读 29
收藏 0

本blog主要介绍: 
1. Codec 编解码器 
2. Decoder 解码器 
3. Encoder 编码器

netty提供了强大的编解码器框架,使得我们编写自定义的编解码器很容易,也容易封装个重用。

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

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

编码器和解码器的结构很简单,消息被编码后解码后会自动通过ReferenceCountUtil.release(message)释放,如果不想释放消息可以使用ReferenceCountUtil.retain(message),这将会使引用数量增加而没有消息发布,大多数时候不需要这么做。


其实,各种编解码器的实现都是ChannelHandler的实现。 

解码器

Netty提供了丰富的解码器抽象基类,我们可以很容易的实现这些基类来自定义解码器。下面是解码器的一个类型:

  • 解码字节到消息
  • 解码消息到消息

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

ByteToMessageDecoder

通常我们需要将消息从 字节 解码成 消息 或者从 字节 解码成其他的 序列化字节 。这是一个常见的任务,Netty提供了抽象基类,我们可以使用它们来实现。Netty中提供的ByteToMessageDecoder可以将字节消息解码成POJO对象,下面列出了ByteToMessageDecoder两个主要方法:

decode(ChannelHandlerContext, ByteBuf, List<Object>)//这个方法是唯一的一个需要自己实现的抽象方法,作用是将ByteBuf数据解码成其他形式的数据。
decodeLast(ChannelHandlerContext, ByteBuf, List<Object>)//实际上调用的是decode(...)。
  • 例如服务器从某个客户端接收到一个整数值的字节码,服务器将数据读入ByteBuf 并经过ChannelPipeline中的每个 ChannelInboundHandle r进行处理,看下图: 

这里写图片描述 
上图显示了从“入站”ByteBuf读取bytes后由 ToIntegerDecoder 进行解码,然后将解码后的消息存入List集合中,然后传递到ChannelPipeline中的下一个ChannelInboundHandler。看下面ToIntegerDecoder的实现代码:

/** 
 * Integer解码器,ByteToMessageDecoder实现 
 * 
 */  
public class ToIntegerDecoder extends ByteToMessageDecoder {  
    @Override  
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {  
        //接收到字节大于4个字节了就处理。
        if(in.readableBytes() >= 4){  
            out.add(in.readInt());  
        }  
    }  
}
  • 从上面的代码可能会发现,我们需要检查ByteBuf读之前是否有足够的字节,这是与TCP黏包有关,若没有这个检查岂不更好?是的,Netty提供了这样的处理允许byte-to-message解码。除了ByteToMessageDecoder之外,Netty还提供了许多其他的解码接口。

ReplayingDecoder

ReplayingDecoder是byte-to-message解码的一种特殊的抽象基类,byte-to-message解码读取缓冲区的数据之前需要检查缓冲区是否有足够的字节,使用ReplayingDecoder就无需自己检查;若ByteBuf中有足够的字节,则会正常读取;若没有足够的字节则会停止解码。也正因为这样的包装使得ReplayingDecoder带有一定的局限性。 
• 不是所有的操作都被ByteBuf支持,如果调用一个不支持的操作会抛出DecoderException。 
• ByteBuf.readableBytes()大部分时间不会返回期望值

如果你能忍受上面列出的限制,相比ByteToMessageDecoder,你可能更喜欢ReplayingDecoder。在满足需求的情况下推荐使用ByteToMessageDecoder,因为它的处理比较简单,没有ReplayingDecoder实现的那么复杂。ReplayingDecoder继承于ByteToMessageDecoder,所以他们提供的接口是相同的。下面代码是ReplayingDecoder的实现:

/**
 * Integer解码器,ReplayingDecoder实现
 */
public class ToIntegerReplayingDecoder extends ReplayingDecoder<Void> {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        out.add(in.readInt());
    }
}
  • 3、MessageToMessageDecoder

将消息对象转成消息对象可是使用MessageToMessageDecoder,它是一个抽象类,需要我们自己实现其decode(…)。message-to-message同上面讲的byte-to-message的处理机制一样,看下图: 
这里写图片描述

实现代码:

/**
 * 将接收的Integer消息转成String类型,MessageToMessageDecoder实现
 * @author c.k
 *
 */
public class IntegerToStringDecoder extends MessageToMessageDecoder<Integer> {

    @Override
    protected void decode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception {
        out.add(String.valueOf(msg));
    }
}
  • 解码器总结

解码器是用来处理入站数据,Netty提供了很多解码器的实现,可以根据需求详细了解。

编码器

Netty提供了一些基类,我们可以很简单的编码器。同样的,编码器有下面两种类型:

  • 消息对象编码成消息对象
  • 消息对象编码成字节码

相对解码器,编码器少了一个byte-to-byte的类型,因为出站数据这样做没有意义。编码器的作用就是将处理好的数据转成字节码以便在网络中传输。对照上面列出的两种编码器类型,Netty也分别提供了两个抽象类:MessageToByteEncoder和MessageToMessageEncoder。下面是类关系图: 
类图

MessageToByteEncoder

MessageToByteEncoder是抽象类,我们自定义一个继承MessageToByteEncoder的编码器只需要实现其提供的encode(…)方法。其工作流程如下图: 
这里写图片描述 
实现代码如下:

/**
 * 编码器,将Integer值编码成byte[],MessageToByteEncoder实现
 */
public class IntegerToByteEncoder extends MessageToByteEncoder<Integer> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Integer msg, ByteBuf out) throws Exception {
        out.writeInt(msg);
    }
}
  • MessageToMessageEncoder

需要将消息编码成其他的消息时可以使用Netty提供的MessageToMessageEncoder抽象类来实现。例如将Integer编码成String,其工作流程如下图: 
这里写图片描述

代码实现如下:

/**
 * 编码器,将Integer编码成String,MessageToMessageEncoder实现
 */
public class IntegerToStringEncoder extends MessageToMessageEncoder<Integer> {

    @Override
    protected void encode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception {
        out.add(String.valueOf(msg));
    }
}

© 著作权归作者所有

刺猬一号
粉丝 12
博文 373
码字总数 616361
作品 0
深圳
私信 提问
Netty 系列六(编解码器).

一、概念 网络传输的单位是字节,如何将应用程序的数据转换为字节,以及将字节转换为应用程序的数据,就要说到到我们该篇介绍的编码器和解码器。 将应用程序的数据转换为网络格式,以及将网络...

JMCui
2018/08/14
0
0
《Netty In Action》第七章 编解码器Codec

本章介绍 Codec,编解码器 Decoder,解码器 Encoder,编码器 Netty提供了编解码器框架,使得编写自定义的编解码器很容易,并且也很容易重用和封装。本章讨论Netty的编解码器框架以及使用。 ...

残刃O
2018/02/05
5
0
第七章:编解码器Codec

本章介绍 Codec,编解码器 Decoder,解码器 Encoder,编码器 7.1 编解码器Codec 编写一个网络应用程序需要实现某种编解码器,编解码器的作用就是讲原始字节数据与自定义的消息对象进行互转。...

李矮矮
2016/09/26
28
0
Netty with protobuf(二)

http://my.oschina.net/xinxingegeya/blog/295031 上一篇了解了protobuf,现在结合netty做一个例子。 关键就是配置netty的编解码器,因为netty提供了protobuf的编解码器,所以我们可以很容易...

秋风醉了
2014/07/26
0
0
Netty源码阅读入门实战(八)-解码

就像很多标准的架构模式都被各种专用框架所支持一样,常见的数据处理模式往往也是目标实现的很好的候选对象,它可以节省开发人员大量的时间和精力。 当然这也适应于本文的主题:编码和解码,或...

芥末无疆sss
2018/10/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

面试爱奇艺,竟然挂在第5轮……

今天给大家分享我曾经在爱奇艺的面试,过程还是比较有意思的,可以给大家一些参考 <br> 聊骚阶段 嗲妹妹:你好,我是爱奇艺的HR,我们正在招聘运维开发岗位,请问您最近有在看工作机会吗? ...

上海小胖
32分钟前
0
0
Jenkins系列_插件安装及报错处理

进入Jenkins之后我们可以进行插件的安装,插件管理位于以下模块: 发现上面报了一堆错误,是因为插件的依赖没有安装好,那么这一节,就先把这些错误解决掉吧。解决完成后,也就基本会使用插件...

shzwork
今天
2
0
mysql mysql的所有查询语句和聚合函数(整理一下,忘记了可以随时看看)

查询所有字段 select * from 表名; 查询自定字段 select 字段名 from 表名; 查询指定数据 select * from 表名 where 条件; 带关键字IN的查询 select * from 表名 where 条件 [not] in(元素...

edison_kwok
昨天
9
0
解决多线程并行加载缓存问题(利用guava实现)

依赖 com.google.guava:guava:20.0 import com.google.common.cache.Cache;import com.google.common.cache.CacheBuilder;import java.util.concurrent.ExecutionException;import j......

暗中观察
昨天
4
0
利用VisualVM 内存查看

准备工作,建几个测试类。等下就是要查看这几个类里面的属性 package visualvm;public class MultiObject { private String str; private int i; MultiObject(String str...

冷基
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部