Netty-LengthFieldBasedFrameDecoder-解决拆包粘包问题的解码器 ...

打印 上一主题 下一主题

主题 891|帖子 891|积分 2673

LengthFieldBasedFrameDecoder 的构造器参数


  • maxFrameLength:指定解码器所能处理的数据包的最大长度,超过该长度则抛出 TooLongFrameException 异常;
  • lengthFieldOffset:指定长度字段的起始位置;
  • lengthFieldLength:指定长度字段的长度:目前支持1(byte)、2(short)、3(3个byte)、4(int)、8(Long)
  • lengthAdjustment:指定长度字段所表示的消息长度值与实际长度值之间的差值,可以用于调整解码器的计算和提高灵活性。
  • initialBytesToStrip:指定解码器在将数据包分离出来后,跳过的字节数,因为这些字节通常不属于消息体内容,而是协议头或其他控制信息。
LengthFieldBasedFrameDecoder测试Demo

有关使用方法和方式参考测试Demo即可。
  1. package com.netty.framework.core.channel;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.buffer.Unpooled;
  4. import io.netty.channel.ChannelHandlerContext;
  5. import io.netty.channel.ChannelInboundHandlerAdapter;
  6. import io.netty.channel.embedded.EmbeddedChannel;
  7. import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
  8. import org.junit.Test;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. import java.nio.charset.StandardCharsets;
  12. /**
  13. * @author 左半边是恶魔
  14. * @date 2023/7/7
  15. * @time 16:10
  16. */
  17. public class LengthFieldBasedFrameDecoderTest {
  18.     private static final Logger LOGGER = LoggerFactory.getLogger(LengthFieldBasedFrameDecoderTest.class);
  19.     // 用于输出内容
  20.     private final ChannelInboundHandlerAdapter handlerAdapter = new ChannelInboundHandlerAdapter() {
  21.         @Override
  22.         public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  23.             LOGGER.debug("handlerAdapter-接收到信息:{}", msg);
  24.             super.channelRead(ctx, msg);
  25.         }
  26.     };
  27.     /**
  28.      * 二进制数据结构
  29.      * lengthFieldOffset   = 0
  30.      * lengthFieldLength   = 4
  31.      * lengthAdjustment    = 0
  32.      * initialBytesToStrip = 0 (不跳过长度字段长度信息读取)
  33.      * 编码前 (16 bytes)                     编码后 (16 bytes)
  34.      * +------------+----------------+      +------------+----------------+
  35.      * |   Length   | Actual Content |----->|   Length   | Actual Content |
  36.      * | 0x0000000C | "Hello, World" |      | 0x0000000C | "Hello, World" |
  37.      * +------------+----------------+      +------------+----------------+
  38.      */
  39.     @Test
  40.     public void test00() {
  41.         class LengthFieldDecoder extends LengthFieldBasedFrameDecoder {
  42.             public LengthFieldDecoder() {
  43.                 super(1024, 0, 4, 0, 0);
  44.             }
  45.             @Override
  46.             protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
  47.                 ByteBuf byteBuf = (ByteBuf) super.decode(ctx, in);
  48.                 LOGGER.debug("长度读取前readerIndex={}", byteBuf.readerIndex());
  49.                 // readInt会更新readerIndex值
  50.                 int lengthField = byteBuf.readInt();
  51.                 LOGGER.debug("长度字段[LengthField]的值={},即(Hello, World)的二进制长度。", lengthField);
  52.                 LOGGER.debug("长度读取后readerIndex={}", byteBuf.readerIndex());
  53.                 // toString方法根据readerIndex最新值开始解码
  54.                 return byteBuf.toString(StandardCharsets.UTF_8);
  55.             }
  56.         }
  57.         LengthFieldBasedFrameDecoder decoder = new LengthFieldDecoder();
  58.         EmbeddedChannel channel = new EmbeddedChannel(decoder, handlerAdapter);
  59.         byte[] bytes = "Hello, World".getBytes(StandardCharsets.UTF_8);
  60.         ByteBuf byteBuf = Unpooled.buffer();
  61.         byteBuf.writeInt(bytes.length);
  62.         byteBuf.writeBytes(bytes);
  63.         channel.writeInbound(byteBuf);
  64.     }
  65.     /**
  66.      * 二进制数据结构
  67.      * lengthFieldOffset   = 0
  68.      * lengthFieldLength   = 4
  69.      * lengthAdjustment    = 0
  70.      * initialBytesToStrip = 4 (跳过长度字段长度信息读取)
  71.      * 编码前 (16 bytes)                     编码后 (12 bytes)
  72.      * +------------+----------------+      +--------+--------+
  73.      * |   Length   | Actual Content |----->|  Actual Content |
  74.      * | 0x0000000C | "Hello, World" |      |  "Hello, World" |
  75.      * +------------+----------------+      +--------+--------+
  76.      */
  77.     @Test
  78.     public void test01() {
  79.         class LengthFieldDecoder extends LengthFieldBasedFrameDecoder {
  80.             public LengthFieldDecoder() {
  81.                 super(1024, 0, 4, 0, 4);
  82.             }
  83.             @Override
  84.             protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
  85.                 ByteBuf byteBuf = (ByteBuf) super.decode(ctx, in);
  86.                 return byteBuf.toString(StandardCharsets.UTF_8);
  87.             }
  88.         }
  89.         LengthFieldBasedFrameDecoder decoder = new LengthFieldDecoder();
  90.         EmbeddedChannel channel = new EmbeddedChannel(decoder, handlerAdapter);
  91.         byte[] bytes = "Hello, World".getBytes(StandardCharsets.UTF_8);
  92.         ByteBuf byteBuf = Unpooled.buffer();
  93.         byteBuf.writeInt(bytes.length);
  94.         byteBuf.writeBytes(bytes);
  95.         channel.writeInbound(byteBuf);
  96.     }
  97.     /**
  98.      * 此处lengthField包含了消息头的长度,即:Length = lengthFieldLength + 消息字节长度(Hello, World的二进制长度)
  99.      * lengthFieldOffset   =  0
  100.      * lengthFieldLength   =  4
  101.      * lengthAdjustment    = -4 (lengthField字段的长度)
  102.      * initialBytesToStrip =  0
  103.      * 编码前 (16 bytes)                     编码后 (16 bytes)
  104.      * +------------+----------------+      +------------+----------------+
  105.      * |   Length   | Actual Content |----->|   Length   | Actual Content |
  106.      * | 0x0000000G | "Hello, World" |      | 0x0000000G | "Hello, World" |
  107.      * +------------+----------------+      +------------+----------------+
  108.      */
  109.     @Test
  110.     public void test02() {
  111.         class LengthFieldDecoder extends LengthFieldBasedFrameDecoder {
  112.             public LengthFieldDecoder() {
  113.                 super(1024, 0, 4, -4, 0);
  114.             }
  115.             @Override
  116.             protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
  117.                 ByteBuf byteBuf = (ByteBuf) super.decode(ctx, in);
  118.                 LOGGER.debug("长度读取前readerIndex={}", byteBuf.readerIndex());
  119.                 // readInt会更新readerIndex值
  120.                 int lengthField = byteBuf.readInt();
  121.                 LOGGER.debug("长度字段[LengthField]的值={},即(Hello, World)的二进制长度。", lengthField);
  122.                 LOGGER.debug("长度读取后readerIndex={}", byteBuf.readerIndex());
  123.                 // toString方法根据readerIndex最新值开始解码
  124.                 return byteBuf.toString(StandardCharsets.UTF_8);
  125.             }
  126.         }
  127.         LengthFieldBasedFrameDecoder decoder = new LengthFieldDecoder();
  128.         EmbeddedChannel channel = new EmbeddedChannel(decoder, handlerAdapter);
  129.         byte[] bytes = "Hello, World".getBytes(StandardCharsets.UTF_8);
  130.         ByteBuf byteBuf = Unpooled.buffer();
  131.         // 4=int的字节长度
  132.         byteBuf.writeInt(bytes.length + 4);
  133.         byteBuf.writeBytes(bytes);
  134.         channel.writeInbound(byteBuf);
  135.     }
  136.     /**
  137.      * lengthField在中间位置
  138.      * lengthFieldOffset   = 2 (= the length of Header 1)
  139.      * lengthFieldLength   = 4
  140.      * lengthAdjustment    = 0
  141.      * initialBytesToStrip = 0
  142.      * <p>
  143.      * BEFORE DECODE (18 bytes)                      AFTER DECODE (18 bytes)
  144.      * +----------+----------+----------------+      +----------+----------+----------------+
  145.      * | Header 1 |  Length  | Actual Content |----->| Header 1 |  Length  | Actual Content |
  146.      * |  0xCAFE  | 0x00000C | "Hello, World" |      |  0xCAFE  | 0x00000C | "Hello, World" |
  147.      * +----------+----------+----------------+      +----------+----------+----------------+
  148.      */
  149.     @Test
  150.     public void test03() {
  151.         class LengthFieldDecoder extends LengthFieldBasedFrameDecoder {
  152.             public LengthFieldDecoder() {
  153.                 super(1024, 2, 4, 0, 0);
  154.             }
  155.             @Override
  156.             protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
  157.                 ByteBuf byteBuf = (ByteBuf) super.decode(ctx, in);
  158.                 LOGGER.debug("长度读取前readerIndex={}", byteBuf.readerIndex());
  159.                 // 读取header1
  160.                 short header1 = byteBuf.readShort();
  161.                 LOGGER.debug("header1={}", header1);
  162.                 // readInt会更新readerIndex值
  163.                 int lengthField = byteBuf.readInt();
  164.                 LOGGER.debug("长度字段[LengthField]的值={},即(Hello, World)的二进制长度。", lengthField);
  165.                 LOGGER.debug("长度读取后readerIndex={}", byteBuf.readerIndex());
  166.                 // toString方法根据readerIndex最新值开始解码
  167.                 return byteBuf.toString(StandardCharsets.UTF_8);
  168.             }
  169.         }
  170.         LengthFieldBasedFrameDecoder decoder = new LengthFieldDecoder();
  171.         EmbeddedChannel channel = new EmbeddedChannel(decoder, handlerAdapter);
  172.         byte[] bytes = "Hello, World".getBytes(StandardCharsets.UTF_8);
  173.         ByteBuf byteBuf = Unpooled.buffer();
  174.         byteBuf.writeShort(99);
  175.         byteBuf.writeInt(bytes.length);
  176.         byteBuf.writeBytes(bytes);
  177.         channel.writeInbound(byteBuf);
  178.     }
  179.     /**
  180.      * lengthField在开始位置
  181.      * lengthFieldOffset   = 0 (= the length of Header 1)
  182.      * lengthFieldLength   = 4
  183.      * lengthAdjustment    = 2
  184.      * initialBytesToStrip = 0
  185.      * BEFORE DECODE (18 bytes)                      AFTER DECODE (18 bytes)
  186.      * +----------+----------+----------------+      +----------+----------+----------------+
  187.      * |  Length  | Header 1 | Actual Content |----->|  Length  | Header 1 | Actual Content |
  188.      * | 0x00000C |  0xCAFE  | "Hello, World" |      | 0x00000C |  0xCAFE  | "Hello, World" |
  189.      * +----------+----------+----------------+      +----------+----------+----------------+
  190.      */
  191.     @Test
  192.     public void test04() {
  193.         class LengthFieldDecoder extends LengthFieldBasedFrameDecoder {
  194.             public LengthFieldDecoder() {
  195.                 super(1024, 0, 4, 2, 0);
  196.             }
  197.             @Override
  198.             protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
  199.                 ByteBuf byteBuf = (ByteBuf) super.decode(ctx, in);
  200.                 LOGGER.debug("长度读取前readerIndex={}", byteBuf.readerIndex());
  201.                 // readInt会更新readerIndex值
  202.                 int lengthField = byteBuf.readInt();
  203.                 LOGGER.debug("长度字段[LengthField]的值={},即(Hello, World)的二进制长度。", lengthField);
  204.                 LOGGER.debug("长度读取后readerIndex={}", byteBuf.readerIndex());
  205.                 // 读取header1
  206.                 short header1 = byteBuf.readShort();
  207.                 LOGGER.debug("header1={}", header1);
  208.                 // toString方法根据readerIndex最新值开始解码
  209.                 return byteBuf.toString(StandardCharsets.UTF_8);
  210.             }
  211.         }
  212.         LengthFieldBasedFrameDecoder decoder = new LengthFieldDecoder();
  213.         EmbeddedChannel channel = new EmbeddedChannel(decoder, handlerAdapter);
  214.         byte[] bytes = "Hello, World".getBytes(StandardCharsets.UTF_8);
  215.         ByteBuf byteBuf = Unpooled.buffer();
  216.         byteBuf.writeInt(bytes.length);
  217.         byteBuf.writeShort(99);
  218.         byteBuf.writeBytes(bytes);
  219.         channel.writeInbound(byteBuf);
  220.     }
  221.     /**
  222.      * lengthFieldOffset   = 1 (= the length of HDR1)
  223.      * lengthFieldLength   = 4
  224.      * lengthAdjustment    = 1 (= the length of HDR2)
  225.      * initialBytesToStrip = 5 (= the length of HDR1 + LEN)
  226.      * BEFORE DECODE (18 bytes)                       AFTER DECODE (13 bytes)
  227.      * +------+--------+------+----------------+      +------+----------------+
  228.      * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
  229.      * | 0xCA | 0x000C | 0xFE | "Hello, World" |      | 0xFE | "Hello, World" |
  230.      * +------+--------+------+----------------+      +------+----------------+
  231.      */
  232.     @Test
  233.     public void test05() {
  234.         class LengthFieldDecoder extends LengthFieldBasedFrameDecoder {
  235.             public LengthFieldDecoder() {
  236.                 super(1024, 1, 4, 1, 5);
  237.             }
  238.             @Override
  239.             protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
  240.                 ByteBuf byteBuf = (ByteBuf) super.decode(ctx, in);
  241.                 LOGGER.debug("长度读取前readerIndex={}", byteBuf.readerIndex());
  242.                 // 读取header2
  243.                 short header2 = byteBuf.readByte();
  244.                 LOGGER.debug("header2={}", header2);
  245.                 // toString方法根据readerIndex最新值开始解码
  246.                 return byteBuf.toString(StandardCharsets.UTF_8);
  247.             }
  248.         }
  249.         LengthFieldBasedFrameDecoder decoder = new LengthFieldDecoder();
  250.         EmbeddedChannel channel = new EmbeddedChannel(decoder, handlerAdapter);
  251.         byte[] bytes = "Hello, World".getBytes(StandardCharsets.UTF_8);
  252.         ByteBuf byteBuf = Unpooled.buffer();
  253.         byteBuf.writeByte(1);
  254.         byteBuf.writeInt(bytes.length);
  255.         byteBuf.writeByte(9);
  256.         byteBuf.writeBytes(bytes);
  257.         channel.writeInbound(byteBuf);
  258.     }
  259.     /**
  260.      * lengthFieldOffset   =  1
  261.      * lengthFieldLength   =  4 (整个消息的长度 = HDR1 + Length + HDR2 + Centent)
  262.      * lengthAdjustment    = -5 (HDR1 + LEN的负值)
  263.      * initialBytesToStrip =  5
  264.      * BEFORE DECODE (18 bytes)                       AFTER DECODE (13 bytes)
  265.      * +------+--------+------+----------------+      +------+----------------+
  266.      * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
  267.      * | 0xCA | 0x0010 | 0xFE | "Hello, World" |      | 0xFE | "Hello, World" |
  268.      * +------+--------+------+----------------+      +------+----------------+
  269.      */
  270.     @Test
  271.     public void test06() {
  272.         class LengthFieldDecoder extends LengthFieldBasedFrameDecoder {
  273.             public LengthFieldDecoder() {
  274.                 super(1024, 1, 4, -5, 5);
  275.             }
  276.             @Override
  277.             protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
  278.                 ByteBuf byteBuf = (ByteBuf) super.decode(ctx, in);
  279.                 LOGGER.debug("长度读取前readerIndex={}", byteBuf.readerIndex());
  280.                 // 读取header2
  281.                 short header2 = byteBuf.readByte();
  282.                 LOGGER.debug("header2={}", header2);
  283.                 // toString方法根据readerIndex最新值开始解码
  284.                 return byteBuf.toString(StandardCharsets.UTF_8);
  285.             }
  286.         }
  287.         LengthFieldBasedFrameDecoder decoder = new LengthFieldDecoder();
  288.         EmbeddedChannel channel = new EmbeddedChannel(decoder, handlerAdapter);
  289.         byte[] bytes = "Hello, World".getBytes(StandardCharsets.UTF_8);
  290.         ByteBuf byteBuf = Unpooled.buffer();
  291.         byteBuf.writeByte(1);
  292.         byteBuf.writeInt(bytes.length + 6);
  293.         byteBuf.writeByte(2);
  294.         byteBuf.writeBytes(bytes);
  295.         channel.writeInbound(byteBuf);
  296.     }
  297. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

惊落一身雪

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表