ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LengthFieldBasedFrameDecoder解码器

2022-05-16 15:33:42  阅读:138  来源: 互联网

标签:报文 bytes length 解码器 LengthFieldBasedFrameDecoder 长度 WORLD HELLO


1参数详解

1.1.1 new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2)

lengthFieldOffset = 0
lengthFieldLength = 2
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" |
 +--------+----------------+      +--------+----------------+
假设请求报文的前两个字节为报文体的长度
并希望服务端能够收到完整的报文
则加入下面这个解码器

pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2));
当加入这个解码器时会调用这个构造方法
public LengthFieldBasedFrameDecoder(
            int maxFrameLength,
            int lengthFieldOffset, int lengthFieldLength) {
        this(maxFrameLength, lengthFieldOffset, lengthFieldLength, 0, 0);
    }
则实际的参数为
 maxFrameLength:Integer.MAX_VALUE(整体报文的最大长度,包括报文头和报文体)
 lengthFieldOffset:0(长度字段的起始索引)
 lengthFieldLength :2(长度字段的长度)
 lengthAdjustment : 0    
 initialBytesToStrip :0

1.组装请求体:
String request = "HELLO, WORLD";
//创建一个字节缓冲区
ByteBuf buffer = Unpooled.buffer();
//写入两个字节的报文体长度,长度为12
buffer.writeShort(request.length());
//写入报文体
buffer.writeBytes(request.getBytes());
//发送
ch.writeAndFlush(buffer);
实际请求体为:
信息: [id: 0x87221f3a, L:/127.0.0.1:52524 - R:/127.0.0.1:8023] WRITE: 14B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 0c 48 45 4c 4c 4f 2c 20 57 4f 52 4c 44       |..HELLO, WORLD  |
+--------+-------------------------------------------------+----------------+

2.在服务端解析
lengthFieldOffset:0(长度字段的起始索引)
 lengthFieldLength :2(长度字段的长度)
从0索引开始读两个字节为报文体的长度,则长度为 00 0c 即长度为12
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        int length = msg.readableBytes();
        System.out.println("请求总长度 = " + length);
        //首先读取两个字节的长度位
        short len = msg.readShort();
        System.out.println("请求报文体的长度 = " + len);
        System.out.println("读取两个字节后的ByteBuf = " + msg);
        //读取报文内容
        byte[] bytes = new byte[len];
        msg.readBytes(bytes, 0, len);
        String request = new String(bytes, Charset.forName("GBK"));
        System.out.println("请求报文体 = " + request);

    }
请求总长度 = 14
请求报文体的长度 = 12
读取两个字节后的ByteBuf = PooledSlicedByteBuf(ridx: 2, widx: 14, cap: 14/14, unwrapped: PooledUnsafeDirectByteBuf(ridx: 14, widx: 14, cap: 1024))
请求报文体 = HELLO, WORLD

1.1.2new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,0,2)

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" |
 +--------+----------------+      +----------------+

假设请求报文的前两个字节为报文体的长度
并希望服务端只接收报文体,丢弃掉长度字节
则加入下面这个解码器
new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,0,2)
请求报文与2.2.1相同
   @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        int length = msg.readableBytes();
        System.out.println("请求总长度 = " + length);
        String s = msg.toString(0, length, Charset.defaultCharset());
        System.out.println("请求报文体 = " + s);
    }
请求总长度 = 12
请求报文体 = HELLO, WORLD

1.1.3new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,-2,0);

lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = -2 (= the length of the Length field)
initialBytesToStrip = 0

 BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
 +--------+----------------+      +--------+----------------+
 | Length | Actual Content |----->| Length | Actual Content |
 | 0x000E | "HELLO, WORLD" |      | 0x000E | "HELLO, WORLD" |
 +--------+----------------+      +--------+----------------+

假设请求报文的前两个字节为总体的长度 
并希望服务端接收全部报文
则加入下面这个解码器
new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,-2,0)

组装请求体
String request = "HELLO, WORLD";
ByteBuf buffer = Unpooled.buffer();
buffer.writeShort(request.length()+2);
buffer.writeBytes(request.getBytes());
信息: [id: 0xa51d3b17, L:/127.0.0.1:56298 - R:/127.0.0.1:8023] WRITE: 14B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 0e 48 45 4c 4c 4f 2c 20 57 4f 52 4c 44       |..HELLO, WORLD  |
+--------+-------------------------------------------------+----------------+

@Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        int length = msg.readableBytes();
        System.out.println("请求总长度 = " + length);
        //读取两个字节的长度位
        short len = msg.readShort();
        System.out.println("报文总长度为 = " + len);
        //报文的请求体为
        String content = msg.toString(2, len-2, Charset.defaultCharset());
        System.out.println("报文请求体为 = " + content);
    }
请求总长度 = 14
报文总长度为 = 14
报文请求体为 = HELLO, WORLD

其他几个参数如下:

 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" |
 +----------+----------+----------------+      +----------+----------+----------------+

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" |
 +----------+----------+----------------+      +----------+----------+----------------+

lengthFieldOffset   = 1 (= the length of HDR1)
 lengthFieldLength   = 2
 lengthAdjustment    = 1 (= the length of HDR2)
 initialBytesToStrip = 3 (= the length of HDR1 + LEN)

 BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
 +------+--------+------+----------------+      +------+----------------+
 | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
 | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
 +------+--------+------+----------------+      +------+----------------+
 

lengthFieldOffset   =  1
 lengthFieldLength   =  2
 lengthAdjustment    = -3 (= the length of HDR1 + LEN, negative)
 initialBytesToStrip =  3

 BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
 +------+--------+------+----------------+      +------+----------------+
 | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
 | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
 +------+--------+------+----------------+      +------+----------------+
 

2解析长度位为字符串的报文

    • 还有的报文长度是用字符串表示的例如:0002AD 前四个字节表示长度位2,AD为报文内容
      则需要自定义解码器,重写getUnadjustedFrameLength
    • 将上述代码做如下修改  
String request = "HELLO, WORLD";
            ByteBuf buffer = Unpooled.buffer();
            //将长度转化为4位字符串
            String strLen = "00"+request.length();
            buffer.writeBytes(strLen.getBytes());
            buffer.writeBytes(request.getBytes());
            ch.writeAndFlush(buffer);

信息: [id: 0x82110268, L:/127.0.0.1:57369 - R:/127.0.0.1:8023] WRITE: 16B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 30 30 31 32 48 45 4c 4c 4f 2c 20 57 4f 52 4c 44 |0012HELLO, WORLD|
+--------+-------------------------------------------------+----------------+

 

2.2自定义解码器

package cn.itbin.decode.server;

import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

import java.nio.ByteOrder;

/**
 * @author chenxiaogao
 * @className MyLFBFD
 * @description TODO
 * @date 2020/11/8
 **/
public class MyLFBFD extends LengthFieldBasedFrameDecoder {
    public MyLFBFD(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
    }

    @Override
    protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
        buf = buf.order(order);
        long frameLength;
        switch (length) {
            case 1:
                frameLength = buf.getUnsignedByte(offset);
                break;
            case 2:
                frameLength = buf.getUnsignedShort(offset);
                break;
            case 3:
                frameLength = buf.getUnsignedMedium(offset);
                break;
            case 4:
                //获取四个字节长度位
                byte[] bytes = new byte[4];
//注意此处使用getBytes,不会改变原有的ByteBuf
                buf.getBytes(0, bytes);
                String strLen = new String(bytes);
                frameLength = Long.valueOf(strLen);
                break;
            case 8:
                frameLength = buf.getLong(offset);
                break;
            default:
                throw new DecoderException(
                        "unsupported lengthFieldLength: " + length + " (expected: 1, 2, 3, 4, or 8)");
        }
        return frameLength;
    }
}

 

标签:报文,bytes,length,解码器,LengthFieldBasedFrameDecoder,长度,WORLD,HELLO
来源: https://www.cnblogs.com/huifeidezhuzai/p/16277068.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有