Netty LengthFieldBasedFrameDecoder

来源:互联网 发布:oracle sql优化 编辑:程序博客网 时间:2024/05/01 06:53

先看看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.   
  6. BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)  
  7. +--------+----------------+      +--------+----------------+  
  8. | Length | Actual Content |----->| Length | Actual Content |  
  9. 0x000C | "HELLO, WORLD" |      | 0x000C | "HELLO, WORLD" |  
  10. +--------+----------------+      +--------+----------------+  


实例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.   
  6. BEFORE DECODE (14 bytes)         AFTER DECODE (12 bytes)  
  7. +--------+----------------+      +----------------+  
  8. | Length | Actual Content |----->| Actual Content |  
  9. 0x000C | "HELLO, WORLD" |      | "HELLO, WORLD" |  
  10. +--------+----------------+      +----------------+  


实例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.   
  6. BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)  
  7. +--------+----------------+      +--------+----------------+  
  8. | Length | Actual Content |----->| Length | Actual Content |  
  9. 0x000E | "HELLO, WORLD" |      | 0x000E | "HELLO, WORLD" |  
  10. +--------+----------------+      +--------+----------------+  


实例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.   
  6. BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)  
  7. +----------+----------+----------------+      +----------+----------+----------------+  
  8. | Header 1 |  Length  | Actual Content |----->| Header 1 |  Length  | Actual Content |  
  9. |  0xCAFE  | 0x00000C | "HELLO, WORLD" |      |  0xCAFE  | 0x00000C | "HELLO, WORLD" |  
  10. +----------+----------+----------------+      +----------+----------+----------------+  


实例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.   
  6. BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)  
  7. +----------+----------+----------------+      +----------+----------+----------------+  
  8. |  Length  | Header 1 | Actual Content |----->|  Length  | Header 1 | Actual Content |  
  9. 0x00000C |  0xCAFE  | "HELLO, WORLD" |      | 0x00000C |  0xCAFE  | "HELLO, WORLD" |  
  10. +----------+----------+----------------+      +----------+----------+----------------+  


实例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.   
  6. BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)  
  7. +------+--------+------+----------------+      +------+----------------+  
  8. | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |  
  9. 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |  
  10. +------+--------+------+----------------+      +------+----------------+  

实例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.   
  6. BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)  
  7. +------+--------+------+----------------+      +------+----------------+  
  8. | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |  
  9. 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |  
  10. +------+--------+------+----------------+      +------+----------------+  


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

1 0
原创粉丝点击