简介
咱们晓得数据在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中提供了上面的几种类型:
STANDARDURL_SAFEORDERED
其中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/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!