Netty详解(七):Netty 编解码以及消息头编解码器

一时失言乱红尘 2022-01-29 13:01 594阅读 0赞

1. MessagePack 概述

MessagePack是一个高效的二进制序列化框架,像JSON一样支持不同语言间的数据交换,速度更快,序列化之后的码流更小。

MessagePacke优点

  • 编解码高效,性能高
  • 序列化后的码流小
  • 支持跨语言

1.1 MessagePack Java API 介绍

  1. <dependencies>
  2. ...
  3. <dependency>
  4. <groupId>org.msgpack</groupId>
  5. <artifactId>msgpack</artifactId>
  6. <version>${ msgpack.version}</version>
  7. </dependency>
  8. ...
  9. </dependencies>

1.2 API 官方示例:

  1. import java.io.IOException;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import org.msgpack.MessagePack;
  5. import org.msgpack.template.Templates;
  6. public class TestMessagePack {
  7. public static void main(String[] args) {
  8. // Create serialize objects
  9. List<String> src=new ArrayList<String>();
  10. src.add("msgpack");
  11. src.add("kumofs");
  12. src.add("viver");
  13. MessagePack msgpack=new MessagePack();
  14. // Serialize
  15. byte[] raw;
  16. try {
  17. raw = msgpack.write(src);
  18. // Deserialize directly using a template
  19. List<String> dst1 = msgpack.read(raw,Templates.tList(Templates.TString));
  20. System.out.println(dst1.get(0));
  21. System.out.println(dst1.get(1));
  22. System.out.println(dst1.get(2));
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }

2. Netty 编码器和解码器开发

2.1 Netty编码器

  1. import org.msgpack.MessagePack;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.handler.codec.MessageToByteEncoder;
  5. public class MsgpackEncoder extends MessageToByteEncoder<Object> {
  6. @Override
  7. protected void encode(ChannelHandlerContext arg0, Object arg1, ByteBuf arg2) throws Exception {
  8. MessagePack msgpack=new MessagePack();
  9. byte[] raw=msgpack.write(arg1);
  10. arg2.writeBytes(raw);
  11. }
  12. }

Netty编码继承MessageToByteEncoder,它负责将Object类型的POJO对象编码成byte数组,然后写入到ByteBuffer中。

2.2 Netty解码器

  1. import java.util.List;
  2. import org.msgpack.MessagePack;
  3. import io.netty.buffer.ByteBuf;
  4. import io.netty.channel.ChannelHandlerContext;
  5. import io.netty.handler.codec.MessageToMessageDecoder;
  6. public class MsgPackDecoder extends MessageToMessageDecoder<ByteBuf> {
  7. @Override
  8. protected void decode(ChannelHandlerContext arg0, ByteBuf arg1, List<Object> arg2) throws Exception {
  9. final byte[] array;
  10. final int length=arg1.readableBytes();
  11. array=new byte[length];
  12. arg1.getBytes(arg1.readerIndex(), array,0,length);
  13. MessagePack msgpack=new MessagePack();
  14. arg2.add(msgpack.read(array));
  15. }
  16. }

Netty解码继承MessageToMessageDecoder,他负责将ByteBuffer类型的数据解码成Object对象。首先从数据报arg1中获取需要解码的byte数组,然后调用MessagePacke的read方法将其反序列化为Object对象,将解码的对象加入到解码列表arg2中,这样就完成了MessagePack解码工作。

3. 利用LengthFieldBasedFrameDecoder解决TCP粘包/拆包

对于TCP粘包 拆包问题来说,最常用的在消息头中新增报文长度字段,然后利用该字段进行半包的编解码。下面我们就利用Netty提供的LengthFieldBasedFrameDecoder和LengthFieldPrepender结合新开发的Netty编解码器来实现对TCP粘包/拆包的支持。

  1. EventLoopGroup group=new NioEventLoopGroup();
  2. try{
  3. Bootstrap b = new Bootstrap();
  4. b.group(group).channel(NioSocketChannel.class)
  5. .option(ChannelOption.TCP_NODELAY, true)
  6. .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
  7. .handler(new ChannelInitializer<SocketChannel>(){
  8. @Override
  9. protected void initChannel(SocketChannel ch) throws Exception {
  10. //LengthFieldBasedFrameDecoder用于处理半包消息
  11. //这样后面的MsgpackDecoder接收的永远是整包消息
  12. ch.pipeline().addLast("frameDecoder",new LengthFieldBasedFrameDecoder(65535,0,2,0,2));
  13. ch.pipeline().addLast("msgpack decoder",new MsgPackDecoder());
  14. //在ByteBuf之前增加2个字节的消息长度字段
  15. ch.pipeline().addLast("frameEncoder",new LengthFieldPrepender(2));
  16. ch.pipeline().addLast("msgpack encoder",new MsgpackEncoder());
  17. ch.pipeline().addLast(new EchoClientHandler(sendNumber));
  18. }
  19. });
  20. ChannelFuture f= b.connect(host,port).sync();
  21. f.channel().closeFuture().sync();
  22. }

在MessagePack编码器之前增加LengthFieldPrepender,它将在ByteBuffer之前增加2个字节的消息长度字段,其原理如下:
在这里插入图片描述

在MessagePack解码器之前增加LengthFieldBasedFrameDecoder,用于处理半包消息,这样后面的MsgpackDecoder接受到的永远是整包消息。它的工作原理如下:
在这里插入图片描述

LengthFieldBasedFrameDecoder构造函数参数列表如下:

  1. * @param maxFrameLength
  2. * the maximum length of the frame. If the length of the frame is
  3. * greater than this value, { @link TooLongFrameException} will be
  4. * thrown.
  5. * @param lengthFieldOffset
  6. * the offset of the length field
  7. * @param lengthFieldLength
  8. * the length of the length field
  9. * @param lengthAdjustment
  10. * the compensation value to add to the value of the length field
  11. * @param initialBytesToStrip
  12. * the number of first bytes to strip out from the decoded frame

发表评论

表情:
评论列表 (有 0 条评论,594人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Netty 解码器

    Netty 编解码 在网络中数据是以字节码二进制的形式传输的,所以我们在使用 Netty 传输数据的时候,需要将我们传输的数据转换为 二进制的形式 进行传输,所以不管是我

    相关 Netty(解码器框架)

        每个网络应用程序都必须定义如何解析在两个节点之间来回传输的原始字节,以及如何将其和目标应用程序的数据格式做相互转换。这种转换逻辑由编解码器处理,编解码器  由编码器和解

    相关 Netty——解码器

    什么是编解码器 每个网络应用程序都必须定义如何解析在两个节点之间来回传输的原始字节,以及如何将其和 目标应用程序的数据格式做相互转换。这种转换逻辑由编解码器处理,编解码器