netty数据解码(netty教程12-长度字段的解码器LengthFieldBasedFrameDecoder详解)

拆包粘包解决方案3-基于长度字段的解码器LengthFieldBasedFrameDecoder

先看LengthFieldBasedFrameDecoder这个类的构造参数:

lengthFieldOffset //长度字段偏移量 lengthFieldLength // 长度字段长度 lengthAdjustment // 以长度字段为基准,还有几个字节是内容 initialBytesToStrip // 从头剥离几个字节

1 发消息时候先发消息内容的长度 下面的例子 HELLO 5个字节 WORLD 5个字节,中间逗号和空格各一个,加起来12, 所以length域值 12,长度字段占2个字节,总共14个字节 lengthFieldOffset = 0 //长度字段偏移量 表示长度域从哪里开始,0表示从头开始 lengthFieldLength = 2 //长度字段长度 长度字段为2说明先读2个个字节,读到 0x000C 知道了消息的长度为12 lengthAdjustment = 0 initialBytesToStrip = 0 (= do not strip Header) BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes) -------- ---------------- -------- ---------------- | Length | Actual Content |----->| Length | Actual Content | | 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" | -------- ---------------- -------- ---------------- 2 我不想要长度字段,想把长度字段从报文里剥离出去,用到最后一个字段 下面的例子 HELLO 5个字节 WORLD 5个字节,中间逗号和空格各一个,加起来12,所以length域值 12,长度字段占2个字节,总共14 lengthFieldOffset = 0 //长度字段偏移量 lengthFieldLength = 2 // 长度字段长度 lengthAdjustment = 0 // 以长度字段为基准,还有几个字节是内容 initialBytesToStrip = 2 (= the length of the Length field) // 从头剥离几个字节 BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes) -------- ---------------- ---------------- | Length | Actual Content |----->| Actual Content | | 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" | -------- ---------------- ---------------- 3 Length字段3个字节,Header占一个2个字节 ,一共占17个字节 发消息时候带上消息头 lengthFieldOffset = 2 (= the length of Header 1) lengthFieldLength = 3 lengthAdjustment = 0 initialBytesToStrip = 0 BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes) ---------- ---------- ---------------- ---------- ---------- ---------------- | Header 1 | Length | Actual Content |----->| Header 1 | Length | Actual Content | | 0xCAFE | 0x00000C | "HELLO, WORLD" | | 0xCAFE | 0x00000C | "HELLO, WORLD" | ---------- ---------- ---------------- ---------- ---------- ---------------- 4 Length字段3个字节,Header占一个2个字节 ,一共占17个字节,以长度字段为基准,还有几个字节是内容 lengthFieldOffset = 0 lengthFieldLength = 3 lengthAdjustment = 2 (= the length of Header 1) // 以长度字段为基准,还有几个字节是内容 initialBytesToStrip = 0 BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes) ---------- ---------- ---------------- ---------- ---------- ---------------- | Length | Header 1 | Actual Content |----->| Length | Header 1 | Actual Content | | 0x00000C | 0xCAFE | "HELLO, WORLD" | | 0x00000C | 0xCAFE | "HELLO, WORLD" | ---------- ---------- ---------------- ---------- ---------- ---------------- 5 HDR1,1个字节 Length 占2个字节 ,HDR2 占1个字节 ,加上内容12个字节一共16个字节 lengthFieldOffset = 1 (= the length of HDR1) // 长度字段偏移量 lengthFieldLength = 2 //长度字段长度 lengthAdjustment = 1 (= the length of HDR2) // 以长度字段为基准,还有几个字节是内容 initialBytesToStrip = 3 (= the length of HDR1 LEN) // 剥离3个字节 所以剩下 HDR2,Actual Content BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes) ------ -------- ------ ---------------- ------ ---------------- | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content | | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" | ------ -------- ------ ---------------- ------ ----------------

上面介绍了LengthFieldBasedFrameDecoder的几种情况:代码:

package com.study.nio.ph2.e6; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.AdaptiveRecvByteBufAllocator; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import lombok.extern.slf4j.Slf4j; /** * @program: isc-study * * @description: 拆包粘包解决方案1--基于长度字段的解码器 LengthFieldBasedFrameDecoder 这里用EmbeddedChannel来测试 * @author: wangjinwei * * 1 发消息时候先发消息内容的长度 * 下面的例子 HELLO 5个字节 WORLD 5个字节,中间逗号和空格各一个,加起来12,所以length域值 12,长度字段占2个字节,总共14 * lengthFieldOffset = 0 //长度字段偏移量 表示长度域从哪里开始,0表示从头开始 * lengthFieldLength = 2 //长度字段长度 长度字段为2说明先读2个个字节,读到 0x000C 知道了消息的长度为12 * lengthAdjustment = 0 * initialBytesToStrip = 0 (= do not strip header) * * BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes) * -------- ---------------- -------- ---------------- * | Length | Actual Content |----->| Length | Actual Content | * | 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" | * -------- ---------------- -------- ---------------- * * 2 我不想要长度字段,想把长度字段从报文里剥离出去,用到最后一个字段 * 下面的例子 HELLO 5个字节 WORLD 5个字节,中间逗号和空格各一个,加起来12,所以length域值 12,长度字段占2个字节,总共14 * lengthFieldOffset = 0 //长度字段偏移量 * lengthFieldLength = 2 // 长度字段长度 * lengthAdjustment = 0 // 以长度字段为基准,还有几个字节是内容 * initialBytesToStrip = 2 (= the length of the Length field) // 从头剥离几个字节 * * BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes) * -------- ---------------- ---------------- * | Length | Actual Content |----->| Actual Content | * | 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" | * -------- ---------------- ---------------- * * 3 Length字段3个字节,Header占一个2个字节 ,一共占17个字节 发消息时候带上消息头 * lengthFieldOffset = 2 (= the length of Header 1) * lengthFieldLength = 3 * lengthAdjustment = 0 * initialBytesToStrip = 0 * * BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes) * ---------- ---------- ---------------- ---------- ---------- ---------------- * | Header 1 | Length | Actual Content |----->| Header 1 | Length | Actual Content | * | 0xCAFE | 0x00000C | "HELLO, WORLD" | | 0xCAFE | 0x00000C | "HELLO, WORLD" | * ---------- ---------- ---------------- ---------- ---------- ---------------- * * 4 Length字段3个字节,Header占一个2个字节 ,一共占17个字节,以长度字段为基准,还有几个字节是内容 * lengthFieldOffset = 0 * lengthFieldLength = 3 * lengthAdjustment = 2 (= the length of Header 1) // 以长度字段为基准,还有几个字节是内容 * initialBytesToStrip = 0 * * BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes) * ---------- ---------- ---------------- ---------- ---------- ---------------- * | Length | Header 1 | Actual Content |----->| Length | Header 1 | Actual Content | * | 0x00000C | 0xCAFE | "HELLO, WORLD" | | 0x00000C | 0xCAFE | "HELLO, WORLD" | * ---------- ---------- ---------------- ---------- ---------- ---------------- * * 5 HDR1,1个字节 Length 占2个字节 ,HDR2 占1个字节 ,加上内容12个字节一共16个字节 * lengthFieldOffset = 1 (= the length of HDR1) // 长度字段偏移量 * lengthFieldLength = 2 //长度字段长度 * lengthAdjustment = 1 (= the length of HDR2) // 以长度字段为基准,还有几个字节是内容 * initialBytesToStrip = 3 (= the length of HDR1 LEN) // 剥离3个字节 所以剩下 HDR2,Actual Content * * BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes) * ------ -------- ------ ---------------- ------ ---------------- * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content | * | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" | * ------ -------- ------ ---------------- ------ ---------------- * * @create: 2021-11-02 14:03 **/ @Slf4j public class Server4 { public static void main(String[] args) { EmbeddedChannel channel = new EmbeddedChannel( new LengthFieldBasedFrameDecoder (1024, 0, 4, 0, 0), new LoggingHandler(LogLevel.INFO) ); ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(); send(buf, "hello, world"); send(buf, "are you ok"); channel.writeAndFlush(buf); } private static void send(ByteBuf buf, String content) { //实际内容 byte[] bytes = content.getBytes(); int len = bytes.length; buf.writeInt(len); buf.writeBytes(bytes); } }

netty数据解码(netty教程12-长度字段的解码器LengthFieldBasedFrameDecoder详解)(1)

运行结果

如果想把长度字段过滤掉:initialBytesToStrip参数传4就可以,把int过滤掉

@Slf4j public class Server4 { public static void main(String[] args) { EmbeddedChannel channel = new EmbeddedChannel( new LengthFieldBasedFrameDecoder (1024, 0, 4, 0, 4), new LoggingHandler(LogLevel.INFO) ); ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(); send(buf, "Hello, world"); send(buf, "Hi!"); channel.writeInbound(buf); } private static void send(ByteBuf buf, String content) { //实际内容 byte[] bytes = content.getBytes(); int len = bytes.length; buf.writeInt(len); buf.writeBytes(bytes); } }

运行结果如下图所示:

netty数据解码(netty教程12-长度字段的解码器LengthFieldBasedFrameDecoder详解)(2)

@Slf4j public class Server4 { public static void main(String[] args) { EmbeddedChannel channel = new EmbeddedChannel( new LengthFieldBasedFrameDecoder (1024, 0, 4, 1, 4), new LoggingHandler(LogLevel.INFO) ); ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(); send(buf, "Hello, world"); send(buf, "Hi!"); channel.writeInbound(buf); } private static void send(ByteBuf buf, String content) { //实际内容 byte[] bytes = content.getBytes(); int len = bytes.length; buf.writeInt(len); //长度后面加了一个字节 buf.writeByte(1); buf.writeBytes(bytes); } }

运行结果如下,第一个是01

netty数据解码(netty教程12-长度字段的解码器LengthFieldBasedFrameDecoder详解)(3)

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页