netty LengthFieldBasedFrameDecoder dubbo消息头

 

Netty 中的拆包器

  1. 固定长度的拆包器 FixedLengthFrameDecoder

  2. 行拆包器 LineBasedFrameDecoder

  3. 分隔符拆包器 DelimiterBasedFrameDecoder

  4. 基于数据包长度的拆包器 LengthFieldBasedFrameDecoder

    前3个比较好理解 按固定长度 或是分隔符进行切割   2和3在源码流程上类似 lineBase是固定模式在定位\n的时候判断前面是否有\r

LengthFieldBasedFrameDecoder 重要的参数有4个 抄自网络

 

  • lengthFieldOffset - 定义长度域位于发送的字节数组中的下标。换句话说:发送的字节数组中下标为${lengthFieldOffset}的地方是长度域的开始地方
  • lengthFieldLength - 用于描述定义的长度域的长度。换句话说:发送字节数组bytes时, 字节数组bytes[lengthFieldOffset, lengthFieldOffset+lengthFieldLength]域对应于的定义长度域部分,unsupported lengthFieldLength: 0 (expected: 1, 2, 3, 4, or 8)
  • lengthAdjustment - 满足公式:
    公式:  数据包值 = 长度域  + lengthFieldOffset+ lengthFieldLength + lengthAdjustment
  • initialBytesToStrip - 接收到的发送数据包,去除前initialBytesToStrip位

 

对于理解这几个参数  假设实际内容长度 放在最前面的情况 消息头跟在后面

bytePuf.writeShort(length);//内容升序

bytePuf.writeByte(1);

bytePuf.writeInt(-21415431);//4

bytePuf.writeShort(11);//

bytePuf.writeShort(22);//

new LengthFieldBasedFrameDecoder(16384, 0, 2, 9, 0)

消息头容量 9= 1+4+2+2 最后一个0 相当于在我们在取的解码内容的时候 从第0个开始 

依次会读到实际内容长度  然后是后面9位消息头 再实际内容

如果最后一个initialBytesToStrip 0 改为11 略过前面11位长度+消息头 可以直接得到消息体内容 

一般使用场景需要验证消息头 

lengthAdjustment 也就是常观 长度(表示内容长度)开头的情况下  值可以理解自定义除去长度 后面定义消息头的容量

另一种情况 长度域如果表示的长度是总长度    这种定义不太好理解 应该尽量避免这种方法去定义

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

长度域表示的长度是总长度 也就是header+body的总长度。参数如下:

lengthFieldOffset=0:开始的2个字节就是长度域,所以不需要长度域偏移。
lengthFieldLength=2:长度域2个字节。
lengthAdjustment=-2:因为长度域为总长度,所以我们需要修正数据长度,也就是减去2。
initialBytesToStrip=0:我们发现接收的数据没有长度域的数据,所以要跳过长度域的2个字节。
————————————————

总结一下这种组织的问题 一般在定义协议的时候 会自定义一个消息头 比如dubbo 固定魔数开头 

还是以上面 9位消息头来说   9位消息头+长度+容量

还是 衣旧上面定义9位消息头 

bytePuf.writeByte(1);

bytePuf.writeInt(-21415431);//4

bytePuf.writeShort(11);//

bytePuf.writeShort(22);//

然后 从第9位取得容量长度  new LengthFieldBasedFrameDecoder(16384, 9, 2, 0, 0)

 

用LengthFieldBasedFrameDecoder定义dubbo消息头 

{

ByteBuf bytePuf = ByteBufAllocator.DEFAULT.buffer();

int length = json.getBytes().length;

bytePuf.writeShort(0xdabb);//MAGIC

bytePuf.writeByte(0x80);//FLAG_REQUEST

bytePuf.writeByte(20);//status

bytePuf.writeLong(System.currentTimeMillis());//invoke id

bytePuf.writeInt(length);//body length:消息体 body 长度

bytePuf.writeBytes(json.getBytes());

cannel.writeAndFlush(bytePuf);

}

 

  LengthFieldBasedFrameDecoder(16384, 12, 4, 0, 0)

{

short magic = buf.readShort();//MAGIC

byte flag = buf.readByte();

byte status = buf.readByte();

long requestId = buf.readLong();

int length = buf.readInt();

}

 

实际LengthFieldBasedFrameDecoder 运用中出现以下异常 

io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 16384: 20033 - discarded

实际可能不是包的长度大于设置最长长度16384

比如 协议内容的长度稍大于的定义的长度

多半是非法请求了 可以跟踪一下限制消息来源ip解决

 所以简单的长度+内容 其实还是比较不安全的 

还是稍微的定义一个协议头 比如什么开头 加个自己的版本号之类

 

 

 


 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值