简介

我们知道数据在netty中传输是以ByteBuf的形式进行的,可以说ByteBuf是netty的数据传输基础。但是对于现代的应用程序来说,通常我们需要用到其他的数据结构或者类型。

为了方便我们在程序中的编写,一种方式就是在将数据传入到netty中的时候由程序员自身将数据格式进行转换,然后再调用netty的系统方法。另外一种方式就是定义一些codec,由netty的内在编码机制将程序中用到的数据格式和ByteBuf进行自动转换。

很明显,使用codec的方式更加简捷,也更加符合程序的开发规则。

为了方便程序的开发,netty本身在内部定义了一些核心的codec插件,我们在需要的时候直接选用即可。

本文将会讲解netty内部实现codec的方式和一个最核心的编码器base64。

netty codec的实现逻辑

所有的netty codec的目的就是在数据传输过程中进行数据类型的转换,换句话说就是对数据进行处理。我们知道netty中有两个对数据进行handler的类,分别是ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter,他们分别对应channel中的inbound消息和outbound消息进行处理。

所以很自然的,我们的codec逻辑只需要在这两个地方添加即可。

netty为我们提供了两个HandlerAdapter类的继承类,分别是MessageToMessageDecoder和MessageToMessageEncoder:

public abstract class MessageToMessageEncoder<I> extends ChannelOutboundHandlerAdapter 

public abstract class MessageToMessageDecoder<I> extends ChannelInboundHandlerAdapter

从名字就可以看出来这两个类分别使用来编码和解码用的,所以我们的codec只需要分别实现这两个类即可。

以下是一个StringToIntegerDecoder和IntegerToStringEncoder的例子:

       public class StringToIntegerDecoder extends
MessageToMessageDecoder<String> { @Override
public void decode(ChannelHandlerContext ctx, String message,
List<Object> out) throws Exception {
out.add(message.length());
}
}
       public class IntegerToStringEncoder extends
MessageToMessageEncoder<Integer> { @Override
public void encode(ChannelHandlerContext ctx, Integer message, List<Object> out)
throws Exception {
out.add(message.toString());
}
}

最简单的实现就是分别重构这两个类的decode和encode方法。

netty中Base64的实现

我们知道JDK中已经有了Base64实现的工具类叫做java.util.Base64。但是在netty中又使用了一个新的实现类同样叫做Base64,它的全称是io.netty.handler.codec.base64.Base64。

这个Base64类中用到了一个Base64Dialect类,也就是netty中Base64支持的Base64编码方式。Base64Dialect中提供了下面的几种类型:

STANDARD
URL_SAFE
ORDERED

其中STANDARD对应的是RFC3548也是JDK中的标准Base64,URL_SAFE对应的是RFC3548中的base64url版本,对应的JDK中的getUrlEncode。

最后一个是ORDERED,代表的是RFC1940,这个编码实现在JDK中是没有的。

为什么JDK中已经有了Base64的工具类,netty中还需要自己创建一个新的类呢?

我们可以考虑一下在netty中Base64用到的场景,通常来说我们是在handler中添加自定义编码,而这些handler主要是针对于数据流进行处理。

JDK中自带的Base64实现在定长的数据上使用还是没问题的,但是如果运用于数据流的处理话,效率就会比较低。所以Netty才需要为base64在流数据的情况下重新实现一个Base64类。

netty中的实现方式使用的是Robert Harder's Public Domain Base64 Encoder/Decoder。这里就不多讲这个算法的实现逻辑了。感兴趣的朋友可以自行探索。

Base64提供了将ByteBuf进行base64编码和解码的方法,我们选择参数最长的方法来观察,如下所示:

    public static ByteBuf encode(
ByteBuf src, int off, int len, boolean breakLines, Base64Dialect dialect, ByteBufAllocator allocator) public static ByteBuf decode(
ByteBuf src, int off, int len, Base64Dialect dialect, ByteBufAllocator allocator)

对于encode方法来说,需要下面几个参数:

  1. ByteBuf类型的src,这是我们需要进行编码的源。
  2. int类型的off和len,表示的是ByteBuf中要编码数据的位置。
  3. boolean类型的breakLines,表示是否添加换行符。
  4. Base64Dialect类型的dialect,表示选择的base64编码类型。
  5. ByteBufAllocator的allocator,表示返回的ByteBuf的生成方式。

同样的Decode方法,需要下面的几个参数:

  1. ByteBuf类型的src,这是我们需要进行解码的源。
  2. int类型的off和len,表示的是ByteBuf中要解码数据的位置。
  3. Base64Dialect类型的dialect,表示选择的base64编码类型。
  4. ByteBufAllocator的allocator,表示返回的ByteBuf的生成方式。

netty中的base64编码和解码器

刚刚我们介绍了netty中提供的新的Base64工具类,这个工具类提供了将ByteBuf中数据进行编码和解码的方法。接下来我们看一下netty是如何使用这个工具类实现netty中的base64编码和解码器。

netty中提供了对Base64的编码和解码器,分别是Base64Encoder和Base64Decoder, 先来看下Base64编码解码器的基本使用:

   ChannelPipeline pipeline = ...;

   // Decoders
pipeline.addLast("frameDecoder", new DelimiterBasedFrameDecoder(80, Delimiters.nulDelimiter()));
pipeline.addLast("base64Decoder", new Base64Decoder()); // Encoder
pipeline.addLast("base64Encoder", new Base64Encoder());

用起来很简单,只需要把Base64Decoder和Base64Encoder添加到pipeline中即可。

有时候Base64Decoder需要和DelimiterBasedFrameDecoder一起使用,尤其是在TCP/IP协议中,因为我们需要根据特定的Delimiters来判断ByteBuf应该被分割为几个frames。这样才能保证数据的有效性。

Base64Encoder

首先来看base64的编码器,Base64Encoder的实现比较简单,首先来看下Base64Encoder的定义:

public class Base64Encoder extends MessageToMessageEncoder<ByteBuf>

Base64Encoder继承自MessageToMessageEncoder,它传入的泛型ByteBuf,表示是将ByteBuf编码为ByteBuf,虽然外部的ByteBuf类型没有变化,但是ByteBuf中的数据已经被编码成为Base64了。

接下来是Base64Encoder的构造函数:

    public Base64Encoder(boolean breakLines, Base64Dialect dialect) {
this.dialect = ObjectUtil.checkNotNull(dialect, "dialect");
this.breakLines = breakLines;
}

Base64Encoder可以接受两个参数,分别是是否有换行符的breakLines和base64编码方式的Base64Dialect。

它的encode方法也很简单:

    protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
out.add(Base64.encode(msg, msg.readerIndex(), msg.readableBytes(), breakLines, dialect));
}

直接使用的是我们上面讲到的Base64工具类的encode方法,然后把返回值添加到out对象中。

Base64Decoder

Base64Decoder用来将ByteBuf中的base64编码的内容解码成为原始内容,先来看下Base64Decoder的定义:

public class Base64Decoder extends MessageToMessageDecoder<ByteBuf>

Base64Decoder继承了MessageToMessageDecoder,传入的泛型是ByteBuf。

先看下Base64Decoder的构造函数:

public Base64Decoder(Base64Dialect dialect) {
this.dialect = ObjectUtil.checkNotNull(dialect, "dialect");
}

Base64Decoder的构造函数很简单,和Base64Encoder相比它只需要一个参数就是Base64Dialect类型的dialect,表示的是选择的base64解码的方式。

接下来就是它的解码方法:

    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
out.add(Base64.decode(msg, msg.readerIndex(), msg.readableBytes(), dialect));
}

解码方法也是调用Base64工具类的decode方法,然后将其添加到返回的out list中去。

总结

本章介绍了netty中的核心编码器Base64,它负责将ByteBuf中的消息编码为base64格式,同时提供了对应的解码器,大家可以在需要的时候进行使用。

本文已收录于 http://www.flydean.com/14-1-netty-codec-base64/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

netty系列之:netty中的核心编码器base64的更多相关文章

  1. 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?

    [读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...

  2. Netty 系列之 Netty 高性能之道 高性能的三个主题 Netty使得开发者能够轻松地接受大量打开的套接字 Java 序列化

    Netty系列之Netty高性能之道 https://www.infoq.cn/article/netty-high-performance 李林锋 2014 年 5 月 29 日 话题:性能调优语言 ...

  3. netty系列之:netty中的核心编码器bytes数组

    目录 简介 byte是什么 netty中的byte数组的工具类 netty中byte的编码器 总结 简介 我们知道netty中数据传输的核心是ByteBuf,ByteBuf提供了多种数据读写的方法,包 ...

  4. netty系列之:netty中的核心解码器json

    目录 简介 java中对json的支持 netty对json的解码 总结 简介 程序和程序之间的数据传输方式有很多,可以通过二进制协议来传输,比较流行的像是thrift协议或者google的proto ...

  5. netty系列之:netty实现http2中的流控制

    目录 简介 http2中的流控制 netty对http2流控制的封装 Http2FlowController Http2LocalFlowController Http2RemoteFlowContr ...

  6. netty系列之:netty中各不同种类的channel详解

    目录 简介 ServerChannel和它的类型 Epoll和Kqueue AbstractServerChannel ServerSocketChannel ServerDomainSocketCh ...

  7. netty系列之:netty架构概述

    目录 简介 netty架构图 丰富的Buffer数据机构 零拷贝 统一的API 事件驱动 其他优秀的特性 总结 简介 Netty为什么这么优秀,它在JDK本身的NIO基础上又做了什么改进呢?它的架构和 ...

  8. Netty系列之Netty可靠性分析

      作者 李林锋 发布于 2014年6月19日 | 29 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件分享 稍后阅读 我的阅读清单   1. 背景 1.1. 宕机的代价 1.1. ...

  9. Netty系列之Netty可靠性分析--转载

    原文地址:http://www.infoq.com/cn/articles/netty-reliability 1. 背景 1.1. 宕机的代价 1.1.1. 电信行业 毕马威国际(KPMG Inte ...

随机推荐

  1. RabbitMQ 的集群?

    镜像集群模式 你创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上,然后 每次你写消息到 queue 的时候,都会自动把消息到多个实例的 queue 里进行消息 同步. 好处 ...

  2. 两个对象值相同(x.equals(y) == true),但却可以有不同的hashcode?

    这个得看情况,如果该对象重写了equals方法,那么可能会出现equals相同,但hashcode不同的情况,但假如没有重写equals方法,那么它默认继承是Object的equals方法,根据源码可 ...

  3. 什么是 Aspect?

    aspect 由 pointcount 和 advice 组成, 它既包含了横切逻辑的定义, 也包 括了连接点的定义. Spring AOP 就是负责实施切面的框架, 它将切面所定义的横 切逻辑编织到 ...

  4. Spring-MVC 里面的ModelAndView

    作用: 由于本身http是无状态的并不会保存什么请求信息.  但是目标页面可能又需要一些信息.这时候可以用ModelAndView存放一些业务数据之类等.然后返回给页面 用法: 比较重要的方法: 往对 ...

  5. JVM原理与深度调优

    什么是jvm jvm是java虚拟机 运行在用户态.通过应用程序实现java代码跨平台.与平台无关.实际上是"一次编译,到处执行" 1.从微观来说编译出来的是字节码!去到哪个平台都 ...

  6. 学习RabbitMQ(一)

    消息中间件 一.简介 消息中间件就是在消息的传输过程中保存消息的容器.消息中间件再将消息从它的源中继到它的目标时充当中间人的作用.队列的主要目的是提供路由并保证消息的传递:如果发送消息时接收者不可用, ...

  7. spi详解

    来源:https://www.sohu.com/a/211324861_468626 1. SPI简介 SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围 ...

  8. js 关于setTimeout和Promise执行顺序问题

    js 关于setTimeout和Promise执行顺序问题 异步 -- Promise和setTimeout 执行顺序   Promise 和 setTimeout 到底谁先执行 定时器的介绍 Jav ...

  9. 一个用于学习的react项目

    React-element 根据开源项目 vue-sell进行的开发,将其改造成了react的项目.在开始学习vue的时候就是用的这个项目,发现效果不错,所以在学习React也使用了此项目. 目的:将 ...

  10. 浅谈JavaScript原型与原型链

    对于很多前端开发者而言,JavaScript的原型实在是很让人头疼,所以我这边就整理了一下自己对应原型的一点理解,分享给大家,供交流使用 原型 说起原型,那就不得不说prototype.__proto ...