乐趣区

关于netty: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 办法来说,须要上面几个参数:

  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/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

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

退出移动版