MessagePack 编解码
MessagePack 是一个高效的二进制序列化框架, 它像 JSON 一样支持不同语言间的数据交换, 但是它的性能更快, 序列化之后的码流更小.
MessagePack 的特点如下:
- 编解码高效, 性能高.
- 序列化之后的码流小.
- 支持跨语言.
MessagePack 编码器和解码器开发
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>5.0.0.Alpha1</version> </dependency>
MessagePack 编码器开发
public class MsgpackEncoder extends MessageToMessageEncoder<Object> { @Override protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception { MessagePack msgpack = new MessagePack(); byte[] bytes = msgpack.write(msg); out.add(bytes); } }
负责将 Object 类型的 POJO 对象编码为 byte 数组, 然后添加到集合中.
MessagePack 解码器开发
public class MsgpackDecoder extends MessageToMessageDecoder<ByteBuf> { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { int length = msg.readableBytes(); byte[] array = new byte[length]; msg.getBytes(msg.readerIndex(), array, 0 , length); MessagePack msgpack = new MessagePack(); out.add(msgpack.read(array)); } }
首先从数据报 msg 中获取需要解码的 byte 数组, 然后调用 MessagePack
的 read
方法将其反序列化为 Objcet
对象, 将解码后的对象加入到 List
集合中. 这样就完成了 MessagePack
的解码操作.
粘包/半包支持
ch.pipeline().addLast("frameDecoder", new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 2)); ch.pipeline().addLast("msgpack decoder", new MsgpackDecoder()); ch.pipeline().addLast("frameEncoder", new LengthFieldPrepender(2)); ch.pipeline().addLast("msgpack encoder", new MsgpackEncoder());
利用 LengthFieldBasedFrameDecoder
和 LengthFieldPrepender
, 结合新开发的 MessagePack
编解码框架, 实现对 TCP 粘包/半包支持.
在 MessagePack
编码器之前增加 LengthFieldPrepender
, 它将在 ByteBuf
之前增加 2 个字节的消息长度字段.
+----------------+ +--------+----------------+ | "HELLO, WORLD" |--->+ 0x000C | "HELLO, WORLD" | +----------------+ +--------+----------------+
在 MessagePack
解码器之前增加 LengthFieldBasedFrameDecoder
, 用于处理半包消息, 这样后面的 MsgpackDecoder
接收到的永远是整包消息.
+--------+----------------+ +----------------+ + 0x000C | "HELLO, WORLD" |--->| "HELLO, WORLD" | +--------+----------------+ +----------------+