先看看LengthFieldBasedFrameDecoder的官方API 
http://docs.jboss.org/netty/3.1/api/org/jboss/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.html

API举例说明了LengthFieldBasedFrameDecoder的解析机制,如下:

实际消息内容是“HELLO, WORLD”,长度是12 bytes(注意逗号后面有一个空格)

实例1 
lengthFieldLength   = 2表示“Length”的长度,而“Length”的值 
就是“Actual Content”的长度(0x000C, 也就是12):

Java代码  

  1. lengthFieldOffset   = 0
  2. lengthFieldLength   = 2
  3. lengthAdjustment    = 0
  4. initialBytesToStrip = 0 (= do not strip header)
  5. BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
  6. +--------+----------------+      +--------+----------------+
  7. | Length | Actual Content |----->| Length | Actual Content |
  8. | 0x000C | "HELLO, WORLD" |      | 0x000C | "HELLO, WORLD" |
  9. +--------+----------------+      +--------+----------------+

实例2 
initialBytesToStrip = 2 表示在decode时,要去掉多少个字节 
在这个例子,表示要去掉“Length”(2个字节) 
可以看到,AFTER DECODE后,“Length”没有了,只剩下“Actual Content”:

Java代码  
  1. lengthFieldOffset   = 0
  2. lengthFieldLength   = 2
  3. lengthAdjustment    = 0
  4. initialBytesToStrip = 2 (= the length of the Length field)
  5. BEFORE DECODE (14 bytes)         AFTER DECODE (12 bytes)
  6. +--------+----------------+      +----------------+
  7. | Length | Actual Content |----->| Actual Content |
  8. | 0x000C | "HELLO, WORLD" |      | "HELLO, WORLD" |
  9. +--------+----------------+      +----------------+

实例3 
与实例1不同,这里“Length”的值不是“Actual Content”的长度,而是 
整个消息的长度(0x000E,14  = 2  + 12)。用lengthAdjustment=-2来表示 
“Actual Content”的长度要减2: 
wholeLength = valueOf(Length) = 14 
actualContentLength = wholeLength + lengthAdjustment = 14 + (-2)=12

Java代码  
  1. lengthFieldOffset   =  0
  2. lengthFieldLength   =  2
  3. lengthAdjustment    = -2 (= the length of the Length field)
  4. initialBytesToStrip =  0
  5. BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
  6. +--------+----------------+      +--------+----------------+
  7. | Length | Actual Content |----->| Length | Actual Content |
  8. | 0x000E | "HELLO, WORLD" |      | 0x000E | "HELLO, WORLD" |
  9. +--------+----------------+      +--------+----------------+

实例4 
这个例子多了一个“Header 1”(oxCAFE,长度为2 ) 
用 lengthFieldOffset   = 2表示“Length”从第3个字节开始 
“Length”的值仍然是“Actual Content ”的长度,不过“Length”自身的 
长度是3 (值是0x00000C,而不是上面的0x000C)

Java代码  
  1. lengthFieldOffset   = 2 (= the length of Header 1)
  2. lengthFieldLength   = 3
  3. lengthAdjustment    = 0
  4. initialBytesToStrip = 0
  5. BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
  6. +----------+----------+----------------+      +----------+----------+----------------+
  7. | Header 1 |  Length  | Actual Content |----->| Header 1 |  Length  | Actual Content |
  8. |  0xCAFE  | 0x00000C | "HELLO, WORLD" |      |  0xCAFE  | 0x00000C | "HELLO, WORLD" |
  9. +----------+----------+----------------+      +----------+----------+----------------+

实例5 
与实例4不同的地方是,“Length”和“Header 1”的位置调换了 
wholeLength = valueOf(Length) = 14 
actualContentLength = wholeLength + lengthAdjustment = 14 + 2=16 
因此在decode时,会认为“Header 1”也是“Actual Content”的一部分

Java代码  
  1. lengthFieldOffset   = 0
  2. lengthFieldLength   = 3
  3. lengthAdjustment    = 2 (= the length of Header 1)
  4. initialBytesToStrip = 0
  5. BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
  6. +----------+----------+----------------+      +----------+----------+----------------+
  7. |  Length  | Header 1 | Actual Content |----->|  Length  | Header 1 | Actual Content |
  8. | 0x00000C |  0xCAFE  | "HELLO, WORLD" |      | 0x00000C |  0xCAFE  | "HELLO, WORLD" |
  9. +----------+----------+----------------+      +----------+----------+----------------+

实例6 
看起来要比之前的例子复杂一些,但其实是上面例子的组合 
lengthFieldOffset = 1表示“Length”从第2个字节开始 
lengthFieldLength   = 2表示“Length”的长度是2 
lengthAdjustment    = 1表示“HDR2”的长度是1: 
wholeLength = valueOf(Length) = 0x000C = 12 
actualContentLength = wholeLength + lengthAdjustment = 12 + 1=13 
decode时,会认为“Length”后面的13个字节都是“Actual Content”, 
因此会认为“HDR2”也是“Actual Content”的一部分 
initialBytesToStrip = 3 表示decode时,去掉3个字节

Java代码  
  1. lengthFieldOffset   = 1 (= the length of HDR1)
  2. lengthFieldLength   = 2
  3. lengthAdjustment    = 1 (= the length of HDR2)
  4. initialBytesToStrip = 3 (= the length of HDR1 + LEN)
  5. BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
  6. +------+--------+------+----------------+      +------+----------------+
  7. | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
  8. | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
  9. +------+--------+------+----------------+      +------+----------------+

实例7 
与实例6不同的是,lengthAdjustment = -3,是负数 
因此, 
wholeLength = valueOf(Length) = 0x0010 = 16 
actualContentLength = wholeLength + lengthAdjustment = 16 + (-3)=13 
decode时,会认为“Length”后面的13个字节都是“Actual Content”, 
最终效果与实例6一样

Java代码  
  1. lengthFieldOffset   =  1
  2. lengthFieldLength   =  2
  3. lengthAdjustment    = -3 (= the length of HDR1 + LEN, negative)
  4. initialBytesToStrip =  3
  5. BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
  6. +------+--------+------+----------------+      +------+----------------+
  7. | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
  8. | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
  9. +------+--------+------+----------------+      +------+----------------+

API看完,我们来看看源码(只保留关键代码):

Java代码  
  1. public class LengthFieldBasedFrameDecoder extends FrameDecoder {
  2. private final int maxFrameLength;   //超出此长度的Frame将被丢弃
  3. private final int lengthFieldOffset;
  4. private final int lengthFieldLength;
  5. private final int lengthFieldEndOffset;     //这个值等于lengthFieldOffset + lengthFieldLength
  6. private final int lengthAdjustment;
  7. private final int initialBytesToStrip;
  8. protected Object decode(
  9. ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
  10. //数据未完整,先不处理
  11. if (buffer.readableBytes() < lengthFieldEndOffset) {
  12. return null;
  13. }
  14. /*
  15. 先读取“Length”的值
  16. 在LengthFieldBasedFrameDecoder的构造函数中,限定了“Length”的长度:
  17. “lengthFieldLength must be either 1, 2, 3, 4, or 8”
  18. 单位是bytes。这个限定不知从何而来,先不管
  19. 由于接收到的数据的类型是ChannelBuffer,也就是byte[],那么在读取时,
  20. 就应该根据长度来分割数据
  21. 例如,lengthFieldLength=3,说明读取前3个字节就得到“Length”的值
  22. 读取时,用到了位操作,ByteOrder是BIG_ENDIAN,因此高位在前,要左移位:
  23. public int getUnsignedMedium(int index) {
  24. return  (array[index]     & 0xff) << 16 |
  25. (array[index + 1] & 0xff) <<  8 |
  26. (array[index + 2] & 0xff) <<  0;
  27. }
  28. 注意到,这个方法不会改变readerIndex
  29. 下面代码的frameLength,其实就是上面API分析时提到的valueOf(Length)
  30. */
  31. int actualLengthFieldOffset = buffer.readerIndex() + lengthFieldOffset;
  32. long frameLength;
  33. switch (lengthFieldLength) {
  34. case 1:
  35. frameLength = buffer.getUnsignedByte(actualLengthFieldOffset);
  36. break;
  37. case 2:
  38. frameLength = buffer.getUnsignedShort(actualLengthFieldOffset);
  39. break;
  40. case 3:
  41. frameLength = buffer.getUnsignedMedium(actualLengthFieldOffset);
  42. break;
  43. case 4:
  44. frameLength = buffer.getUnsignedInt(actualLengthFieldOffset);
  45. break;
  46. case 8:
  47. frameLength = buffer.getLong(actualLengthFieldOffset);
  48. break;
  49. default:
  50. throw new Error("should not reach here");
  51. }
  52. //如分析API时所说,要加上lengthAdjustment
  53. //那为什么 还要加上lengthFieldEndOffset?
  54. //加上之后,frameLength就代表整个frame的长度了,包括前缀和“Actual Content”
  55. frameLength += lengthAdjustment + lengthFieldEndOffset;
  56. int frameLengthInt = (int) frameLength;
  57. //数据未完整,先不处理
  58. if (buffer.readableBytes() < frameLengthInt) {
  59. return null;
  60. }
  61. //readerIndex往后移,跳过指定的字节,不读取
  62. buffer.skipBytes(initialBytesToStrip);
  63. // extract frame ,读取消息的内容
  64. int readerIndex = buffer.readerIndex();
  65. int actualFrameLength = frameLengthInt - initialBytesToStrip;
  66. ChannelBuffer frame = extractFrame(buffer, readerIndex, actualFrameLength);
  67. //extractFrame方法不改变buffer的readerIndex,因此要手动设置
  68. buffer.readerIndex(readerIndex + actualFrameLength);
  69. return frame;
  70. }
  71. //这个方法创建了新的ChannelBuffer,不影响原buffer
  72. protected ChannelBuffer extractFrame(ChannelBuffer buffer, int index, int length) {
  73. ChannelBuffer frame = buffer.factory().getBuffer(length);
  74. frame.writeBytes(buffer, index, length);
  75. return frame;
  76. }
  77. }

Netty——LengthFieldBasedFrameDecoder相关推荐

  1. Netty LengthFieldBasedFrameDecoder

    先看看LengthFieldBasedFrameDecoder的官方API  http://docs.jboss.org/netty/3.1/api/org/jboss/netty/handler/c ...

  2. Netty源码学习-LengthFieldBasedFrameDecoder

    先看看LengthFieldBasedFrameDecoder的官方API [url]http://docs.jboss.org/netty/3.1/api/org/jboss/netty/handl ...

  3. Netty源码(十一)之LengthFieldBasedFrameDecoder/LengthFieldPrepender

    1.前文 前两篇博客我介绍了三种解码器,分别是基于固定长度的解码器(FixedLengthFrameDecoder),基于行的解码器(LineBasedFrameDecoder),基于分割符解码器(D ...

  4. netty粘包拆包之LengthFieldBasedFrameDecoder解码器

    ​目录           一. 背景简介           二. 应用           三.源码 一.背景简介 LengthFieldBasedFrameDecoder 基于长度字段解码器,是 ...

  5. Netty源码分析系列之常用解码器(下)——LengthFieldBasedFrameDecoder

    扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 前言 在上一篇文章中分析了三个比较简单的解码器,今天接着分析最后一个常用的解码器:Leng ...

  6. netty集成ssl完整参考指南(含完整源码)

    虽然我们在内部rpc通信中使用的是基于认证和报文头加密的方式实现安全性,但是有些时候仍然需要使用SSL加密,可能是因为对接的三方系统需要,也可能是由于open的考虑.中午特地测了下netty下集成ss ...

  7. Netty 粘包 拆包 编码 解码 序列化 介绍

    目录: 粘包 & 拆包及解决方案 ByteToMessageDecoder 基于长度编解码器 基于分割符的编解码器 google 的 Protobuf 序列化介绍 其他的 前言 Netty 作 ...

  8. 附录G Netty与NettyUtils

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/beliefer/article/details/77450134 注:本文是为了配合<Spar ...

  9. 面试官问:服务的心跳机制与断线重连,Netty底层是怎么实现的?懵了

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 心跳机制 何为心跳 所谓心跳, 即在 TCP 长连接中, ...

最新文章

  1. Python教程:迭代器的正确使用方法
  2. mybatis中使用XML配置文件方式实现CRUD模板流程
  3. VTK:可视化之ScalarVisibility
  4. nginx系列之七:限流配置
  5. 离散数学:构造性二难推理和破坏性二难定理的解释
  6. python爬虫爬取慕课网中的图片
  7. fckeditor出现the server didn't send back a proper XML response问题的解决(因为使用了“主题”)...
  8. Java 安装包下载地址
  9. Autumn2.0.1_WP扁平化博客自媒体文章资讯类网站模板
  10. 生成对抗网络(六)----------Image Denoising Using a Generative Adversarial Network(用GAN对图像去噪)
  11. 十分钟教你学会打包APP
  12. 什么是SAS硬盘,服务器硬盘sas和sata有什么区别
  13. IDEA括起选中的选中的内容
  14. 解决ORA-01111, ORA-01110, ORA-01157
  15. Android EventBus使用
  16. php面试理论之精选
  17. java 企业版_下列版本中哪个是Java 企业版
  18. 定时器的几种实现方案
  19. 11.21 if条件语句 年月日执行判断
  20. modbus从机模拟软件:modbus Slave和modsim

热门文章

  1. 特别记事本这款文字编辑器怎么样
  2. 全国31省实际利用外资数据集(1978-2019年)
  3. IT高管和易筋经的故事
  4. python3之多线程(应用一)
  5. 世界各个国家坐标位置和中国各个省份坐标位置json格式
  6. Hadoop——Hadoop优势、组成、大数据技术生态体系、系统框架图
  7. 前端性能优化之图片优化
  8. 【电子元件】常用电子元器件实物图大全
  9. php分页实例,php分页代码简单实现教程
  10. 关于偏函数的理解与实例(functools.partial)