简介

netty之所以弱小,是因为它内置了很多十分有用的编码解码器,通过应用这些编码解码器能够很不便的搭建出十分弱小的应用程序,明天给大家讲讲netty中最根本的内置编码解码器。

netty中的内置编码器

在对netty的包进行引入的时候,咱们能够看到netty有很多以netty-codec结尾的artifactId,统计一下,有这么多个:

netty-codecnetty-codec-httpnetty-codec-http2netty-codec-memcachenetty-codec-redisnetty-codec-socksnetty-codec-stompnetty-codec-mqttnetty-codec-haproxynetty-codec-dns

总共10个codec包,其中netty-codec是最根底的一个,其余的9个是对不同的协定包进行的扩大和适配,能够看到netty反对罕用的和风行的协定格局,十分的弱小。因为codec的内容十分多,要解说他们也不是很容易,本文将会以netty-codec做一个例子,解说其中最根本的也是最通用的编码解码器。

应用codec要留神的问题

尽管netty提供了很不便的codec编码解码器,然而正如咱们在前一篇文章中提到的,有些codec是须要和Frame detection一起配合应用的,先应用Frame detection将ByteBuf拆分成一个个代表实在数据的ByteBuf,再交由netty内置的codec或者自定义的codec进行解决,这样能力起到应有的成果。

netty内置的根本codec

netty中根本的codec有base64、bytes、compression、json、marshalling、protobuf、serialization、string和xml这几种。

上面将会一一进行解说。

base64

这个codec是负责ByteBuf和base64过后的ByteBuf之间的转换。尽管都是从ByteBuf到ByteBuf,然而其中的内容产生了变动。

有两个要害的类,别离是Base64Encoder和Base64Decoder。因为Base64Decoder是一个MessageToMessageDecoder,所以须要应用一个DelimiterBasedFrameDecoder提前进行解决,罕用的例子如下:

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

bytes

bytes是将bytes数组和ByteBuf之间进行转换,同样的在decode之前,也须要应用FrameDecoder,通常的应用形式如下:

   ChannelPipeline pipeline = ...;     // Decoders   pipeline.addLast("frameDecoder",                    new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));   pipeline.addLast("bytesDecoder",                    new ByteArrayDecoder());     // Encoder   pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));   pipeline.addLast("bytesEncoder", new ByteArrayEncoder());   

compression

compression这个包的内容就比拟丰盛了,次要是对数据的压缩和解压缩服务。其反对的算法如下:

brotliBzip2FastLZJdkZlibLz4LzfSnappyZlibZstandard

compression对于大数据量的传输特地有帮忙,通过压缩能够节俭传输的数据量,从而进步传输速度。

然而压缩是应用特定的算法来计算的,所以它是一个高CPU的操作,咱们在应用的时候须要兼顾网络速度和CPU性能,并从中失去均衡。

json

json这个包外面只有一个JsonObjectDecoder类,次要负责将Byte流的JSON对象或者数组转换成JSON对象和数组。

JsonObjectDecoder间接就是一个ByteToMessageDecoder的子类,所以它不须要FrameDecoder,它是依据括号的匹配来判断Byte数组的起始地位,从而辨别哪些Byte数据是属于同一个Json对象或者数组。

咱们如果心愿应用JSON来传输数据的话,这个类就十分有用了。

marshalling

Marshalling的全称叫做JBoss Marshalling,它是JBoss出品的一个对象序列化的形式,然而JBoss Marshalling的最新API还是在2011-04-27,曾经有10年没更新了,是不是曾经被废除了?

所以这里咱们不具体介绍这个序列化的内容,感兴趣的小伙伴能够自行摸索。

protobuf

protobuf大家应该都很相熟了,它是google出品的一种信息替换格局,能够将其看做是一种序列化的形式。它是语言中立、平台中立、可扩大的结构化数据序列化机制,和XML相似,然而比XML更小、更快、更简略。

netty对protobuf的反对在于能够将protobuf中的message和MessageLite对象跟ByteBuf进行转换。

protobuf的两个编码器也是message到message间接的转换,所以也须要应用frame detection。当然你也能够应用其余的frame detection比方LengthFieldPrepender和LengthFieldBasedFrameDecoder如下所示:

   ChannelPipeline pipeline = ...;     // Decoders   pipeline.addLast("frameDecoder",                    new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));   pipeline.addLast("protobufDecoder",                    new ProtobufDecoder(MyMessage.getDefaultInstance()));     // Encoder   pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));   pipeline.addLast("protobufEncoder", new ProtobufEncoder());

其中LengthFieldPrepender会主动给字段后面加上一个长度字段:

之前:   +----------------+   | "HELLO, WORLD" |   +----------------+之后:   +--------+----------------+   + 0x000C | "HELLO, WORLD" |   +--------+----------------+

当然netty为protobuf筹备了两个专门的frame detection,他们是ProtobufVarint32FrameDecoder和ProtobufVarint32LengthFieldPrepender。在解说这两个类之前,咱们须要理解一下protobuf中的Base 128 Varints。

什么叫Varints呢?就是序列化整数的时候,占用的空间大小是不一样的,小的整数占用的空间小,大的整数占用的空间大,这样不必固定一个具体的长度,能够缩小数据的长度,然而会带来解析的复杂度。

那么怎么晓得这个数据到底须要几个byte呢?在protobuf中,每个byte的最高位是一个判断位,如果这个位被置位1,则示意前面一个byte和该byte是一起的,示意同一个数,如果这个位被置位0,则示意前面一个byte和该byte没有关系,数据到这个byte就完结了。

举个例子,一个byte是8位,如果示意的是整数1,那么能够用上面的byte来示意:

0000 0001

如果一个byte装不下的整数,那么就须要应用多个byte来进行连贯操作,比方上面的数据表示的是300:

1010 1100 0000 0010

为什么是300呢?首先看第一个byte,它的首位是1,示意前面还有一个byte。再看第二个byte,它的首位是0,示意到此就完结了。咱们把判断位去掉,变成上面的数字:

010 1100 000 0010

这时候还不能计算数据的值,因为在protobuf中,byte的位数是反过来的,所以咱们须要把下面的两个byte替换一下地位:

000 0010 010 1100 

也就是:

10 010 1100 

=256 + 32 + 8 + 4 = 300

在protobuf中个别应用Varint作为字段的长度位,所以netty提供了ProtobufVarint32LengthFieldPrepender和ProtobufVarint32FrameDecoder对ByteBuf进行转换。

比方为ByteBuf增加varint的length:

   BEFORE ENCODE (300 bytes)       AFTER ENCODE (302 bytes)   +---------------+               +--------+---------------+   | Protobuf Data |-------------->| Length | Protobuf Data |   |  (300 bytes)  |               | 0xAC02 |  (300 bytes)  |   +---------------+               +--------+---------------+

解码的时候删除varint的length字段:

   BEFORE DECODE (302 bytes)       AFTER DECODE (300 bytes)   +--------+---------------+      +---------------+   | Length | Protobuf Data |----->| Protobuf Data |   | 0xAC02 |  (300 bytes)  |      |  (300 bytes)  |   +--------+---------------+      +---------------+

serialization

序列化就是把对象转换成二进制数据,事实上所有的codec都能够成为序列化。他们提供了对象和byte之间的转换方法。

netty也提供了两个对象的转换方法:ObjectDecoder和ObjectEncoder。

要留神的是,这两个对象和JDK自带的ObjectInputStream和ObjectOutputStream,是不兼容的,如果要兼容,能够应用CompactObjectInputStream、CompactObjectOutputStream和CompatibleObjectEncoder。

string

String是咱们最常应用到的对象,netty为string提供了StringDecoder和StringEncoder。

同样的,在应用这两个类之前,须要将音讯进行转换,通常应用的是 LineBasedFrameDecoder按行进行转换:

   ChannelPipeline pipeline = ...;     // Decoders   pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(80));   pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));     // Encoder   pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));

xml

xml也是一个十分罕用的格局,然而它的体积会比拟大,当初应该用的比拟少了。netty提供了一个XmlFrameDecoder来进行解析。

因为xml有本人的开始和结束符,所以不须要再做frame detection,间接转换即可,如:

   +-----+-----+-----------+   | <an | Xml | Element/> |   +-----+-----+-----------+转换成:   +-----------------+   | <anXmlElement/> |   +-----------------+
   +-----+-----+-----------+-----+----------------------------------+   | <an | Xml | Element/> | <ro | ot><child>content</child></root> |   +-----+-----+-----------+-----+----------------------------------+   转换成:   +-----------------+-------------------------------------+   | <anXmlElement/> | <root><child>content</child></root> |   +-----------------+-------------------------------------+

都是能够的。

总结

netty提供了很多优良的codec来适配各种利用协定,大家能够多用用,找找不同协定的不同之处。

本文已收录于 http://www.flydean.com/16-netty-buildin-codec-common/

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

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