netty系列之:netty中的核心编码器base64
简介
我们知道数据在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方法来说,需要下面几个参数:
- ByteBuf类型的src,这是我们需要进行编码的源。
- int类型的off和len,表示的是ByteBuf中要编码数据的位置。
- boolean类型的breakLines,表示是否添加换行符。
- Base64Dialect类型的dialect,表示选择的base64编码类型。
- ByteBufAllocator的allocator,表示返回的ByteBuf的生成方式。
同样的Decode方法,需要下面的几个参数:
- ByteBuf类型的src,这是我们需要进行解码的源。
- int类型的off和len,表示的是ByteBuf中要解码数据的位置。
- Base64Dialect类型的dialect,表示选择的base64编码类型。
- 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的更多相关文章
- 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?
[读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...
- Netty 系列之 Netty 高性能之道 高性能的三个主题 Netty使得开发者能够轻松地接受大量打开的套接字 Java 序列化
Netty系列之Netty高性能之道 https://www.infoq.cn/article/netty-high-performance 李林锋 2014 年 5 月 29 日 话题:性能调优语言 ...
- netty系列之:netty中的核心编码器bytes数组
目录 简介 byte是什么 netty中的byte数组的工具类 netty中byte的编码器 总结 简介 我们知道netty中数据传输的核心是ByteBuf,ByteBuf提供了多种数据读写的方法,包 ...
- netty系列之:netty中的核心解码器json
目录 简介 java中对json的支持 netty对json的解码 总结 简介 程序和程序之间的数据传输方式有很多,可以通过二进制协议来传输,比较流行的像是thrift协议或者google的proto ...
- netty系列之:netty实现http2中的流控制
目录 简介 http2中的流控制 netty对http2流控制的封装 Http2FlowController Http2LocalFlowController Http2RemoteFlowContr ...
- netty系列之:netty中各不同种类的channel详解
目录 简介 ServerChannel和它的类型 Epoll和Kqueue AbstractServerChannel ServerSocketChannel ServerDomainSocketCh ...
- netty系列之:netty架构概述
目录 简介 netty架构图 丰富的Buffer数据机构 零拷贝 统一的API 事件驱动 其他优秀的特性 总结 简介 Netty为什么这么优秀,它在JDK本身的NIO基础上又做了什么改进呢?它的架构和 ...
- Netty系列之Netty可靠性分析
作者 李林锋 发布于 2014年6月19日 | 29 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件分享 稍后阅读 我的阅读清单 1. 背景 1.1. 宕机的代价 1.1. ...
- Netty系列之Netty可靠性分析--转载
原文地址:http://www.infoq.com/cn/articles/netty-reliability 1. 背景 1.1. 宕机的代价 1.1.1. 电信行业 毕马威国际(KPMG Inte ...
随机推荐
- jdk源码阅读笔记
1.环境搭建 http://www.komorebishao.com/2020/idea-java-jdk-funyard/ 2. 好的源码阅读资源 https://zhuanlan.zhihu.co ...
- 假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以 某个固定的已知的前缀开头的,如果将它们全部找出来?
使用 keys 指令可以扫出指定模式的 key 列表. 对方接着追问:如果这个 redis 正在给线上的业务提供服务,那使用 keys 指令会 有什么问题? 这个时候你要回答 redis 关键的一个特 ...
- SpringBean的生命周期 以及一些问题总结
SpringBean的生命周期 一.传统 Bean 的生命周期 new实例化: 可使用了 无引用时,GC回收. 二.Servlet 的生命周期 实例化Servlet对象: init初始化对象: 相应客 ...
- 如何在 Mac 上强制退出 App
同时按住三个按键:Option.Command 和 Esc (Escape) 键.或者,从屏幕左上角的苹果菜单 中选取"强制退出".(这类似于在 PC 上按下 Control- ...
- Log4j使用(转)
from:http://www.cnblogs.com/ITtangtang/p/3926665.html 一.Log4j简介Log4j有三个主要的组件:Loggers(记录器),Appenders ...
- JavaScript ajax返回状态
该内容转自CSDN:http://blog.csdn.net/u013381651/article/details/51261956 xmlhttp.readyState的值及解释: 0:请求未初始化 ...
- 用 Java 写一个折半查找?
折半查找,也称二分查找.二分搜索,是一种在有序数组中查找某一特定元素的搜索算法. 搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束:如果某一特定元素大于或者小于中间元素,则 ...
- 什么是基于 Java 的 Spring 注解配置?
基于 Java 的配置,允许你在少量的 Java 注解的帮助下,进行你的大部分 Spring 配置而非通过 XML 文件. 以@Configuration 注解为例,它用来标记类可以当做一个 bean ...
- Spring与Web项目整合的原理
引言: 在刚开始我们接触IOC时,我们加载并启用SpringIOC是通过如下代码手动加载 applicationContext.xml 文件,new出context对象,完成Bean的创建和属性的注入 ...
- 学习SVN03
SVN版本控制系统最佳实践 第1章SVN介绍及应用场景 1.1什么是SVN(Subversion) Svn(subversion)是近年来崛起非常优秀的版本管理工具,与CVS管理工具一样,SVN是 ...