您的位置:首页 > 其它

netty 数据分包、组包、粘包处理机制(二)

2014-09-18 16:26 363 查看

(5)LengthFieldBasedFrameDecoder

常用的处理大数据分包传输问题的解决类,先对构造方法LengthFieldBasedFrameDecoder中的参数做以下解释说明“maxFrameLength:解码的帧的最大长度lengthFieldOffset:长度属性的起始位(偏移位),包中存放有整个大数据包长度的字节,这段字节的其实位置lengthFieldLength:长度属性的长度,即存放整个大数据包长度的字节所占的长度lengthAdjustmen:长度调节值,在总长被定义为包含包头长度时,修正信息长度。initialBytesToStrip:跳过的字节数,根据需要我们跳过lengthFieldLength个字节,以便接收端直接接受到不含“长度属性”的内容failFast:为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常,为false,读取完整个帧再报异常下面对各种情况分别描述:1.2byteslengthfieldatoffset0,donotstripheaderlengthFieldOffset=0lengthFieldLength=2lengthAdjustment=0initialBytesToStrip=0(=donotstripheader)
BEFOREDECODE(14bytes)AFTERDECODE(14bytes)
+--------+----------------++--------+----------------+|Length|ActualContent|---->|Length|ActualContent||0x000C|"HELLO,WORLD"||0x000C|"HELLO,WORLD"|+--------+----------------++--------+----------------+此时数据格式不做任何改变(没有跳过任何字节)2.2byteslengthfieldatoffset0,stripheaderlengthFieldOffset=0lengthFieldLength=2lengthAdjustment=0initialBytesToStrip=2(=thelengthoftheLengthfield)
BEFOREDECODE(14bytes)AFTERDECODE(12bytes)
+--------+----------------++----------------+
|Length|ActualContent|---->|ActualContent|
|0x000C|"HELLO,WORLD"||"HELLO,WORLD"|
+--------+----------------++----------------+
此时帧长度为14个字节,但由于前[/b](lengthFieldOffset=0)两个[/b](lengthFieldLength=2)字节是表示帧长度的字节,不计入数据,故真实的数据长度为12个字节。3.2byteslengthfieldatoffset0,donotstripheader,thelengthfieldrepresentsthelengthofthewholemessagelengthFieldOffset=0lengthFieldLength=2lengthAdjustment=-2(=thelengthoftheLengthfield)initialBytesToStrip=0
BEFOREDECODE(14bytes)AFTERDECODE(14bytes)
+--------+----------------++--------+----------------+
|Length|ActualContent|---->|Length|ActualContent|
|0x000E|"HELLO,WORLD"||0x000E|"HELLO,WORLD"|
+--------+----------------++--------+----------------+
此处定义的Length为0x000E共占了两个字节,表示的帧长度为14个字节,前[/b](lengthFieldOffset=0)两个[/b](lengthFieldLength=2)字节为Length,由于设置的lengthAdjustment=-2(=thelengthoftheLengthfield),故修正的信息实际长度补2,即解码时往前推2个字节,解码后还是14个字节长度(此种情况是把整个长度封装,一般来讲,我们只封装数据长度)4.3byteslengthfieldattheendof5bytesheader,donotstripheaderlengthFieldOffset=2(=thelengthofHeader1)lengthFieldLength=3lengthAdjustment=0initialBytesToStrip=0
BEFOREDECODE(17bytes)AFTERDECODE(17bytes)
+---------+---------+--------------++---------+---------+------------+
|Header1|Length|ActualContent|--->|Header1|Length|ActualContent|
|0xCAFE|0x00000C|"HELLO,WORLD"||0xCAFE|0x00000C|"HELLO,WORLD"|
+---------+---------+--------------++----------+--------+-----------+
此处lengthFieldOffset=2,从第3个字节开始表示数据长度,长度占3个字节,真实数据长度为0x00000C即12个字节,而lengthAdjustment=0,initialBytesToStrip=0,故解码后的数据与解码前的数据相同。4.3byteslengthfieldatthebeginningof5bytesheader,donotstripheaderlengthFieldOffset=0lengthFieldLength=3lengthAdjustment=2(=thelengthofHeader1)initialBytesToStrip=0
BEFOREDECODE(17bytes)AFTERDECODE(17bytes)
+----------+----------+----------------++----------+----------+----------------+
|Length|Header1|ActualContent|----->|Length|Header1|ActualContent|
|0x00000C|0xCAFE|"HELLO,WORLD"||0x00000C|0xCAFE|"HELLO,WORLD"|
+----------+----------+----------------++----------+----------+----------------+
此处由于修正的字节数是2,且initialBytesToStrip=0,故整个数据的解码数据保持不变总字节数是17,开始的三个字节表示字节长度:12,修正的字节是2,(即从第三个字节开始,再加两个开始是真正的数据,其中跳过的字节数是0)5.2byteslengthfieldatoffset1inthemiddleof4bytesheader,stripthefirstheaderfieldandthelengthfieldlengthFieldOffset=1(=thelengthofHDR1)lengthFieldLength=2lengthAdjustment=1(=thelengthofHDR2)initialBytesToStrip=3(=thelengthofHDR1+LEN)BEFOREDECODE(16bytes)AFTERDECODE(13bytes)+------+--------+------+----------------++------+----------------+|HDR1|Length|HDR2|ActualContent|----->|HDR2|ActualContent||0xCA|0x000C|0xFE|"HELLO,WORLD"||0xFE|"HELLO,WORLD"|+------+--------+------+----------------++------+----------------+从第2个字节开始解码,取两个字节作为帧长度,为12个字节,然后,修正一个字节,从第5个字节到最后表示帧数据,解码时,由于initialBytesToStrip=3,表示跳过前三个字节(去掉),故从第四个字节开始解析,解析出来后,如右图所示。6.2byteslengthfieldatoffset1inthemiddleof4bytesheader,stripthefirstheaderfieldandthelengthfield,thelengthfieldrepresentsthelengthofthewholemessagelengthFieldOffset=1lengthFieldLength=2lengthAdjustment=-3(=thelengthofHDR1+LEN,negative)initialBytesToStrip=3BEFOREDECODE(16bytes)AFTERDECODE(13bytes)+------+--------+------+----------------++------+----------------+|HDR1|Length|HDR2|ActualContent|----->|HDR2|ActualContent||0xCA|0x0010|0xFE|"HELLO,WORLD"||0xFE|"HELLO,WORLD"|+------+--------+------+----------------++------+----------------+从第二个字节开始,取两个字节作为帧长度,为16个字节,然后补3个字节,故往前找三个字节,从HDP1开始解码,而又因为initialBytesToStrip=3,解码时忽略掉前三个字节,故从第四个字节开始解析,解析结果如右图所示。总结:一般来讲,当lengthAdjustment为负数时,Length表示的是整个帧的长度,当lengthAdjustment为正数或0时,表示真实数据长度。

(6)LengthFieldPrepender

编码类,自动将+----------------+|"HELLO,WORLD"|+----------------+格式的数据转换成+--------+----------------++0x000C|"HELLO,WORLD"|+--------+----------------+格式的数据,
如果lengthIncludesLengthFieldLength设置为true,则编码为
+--------+----------------++0x000E|"HELLO,WORLD"|+--------+----------------+格式的数据应用场景:自定义pipelineFactory类:MyPipelineFactoryimplementsChannelPipelineFactory中pipeline.addLast("frameEncode",newLengthFieldPrepender(4,false));

(7)TooLongFrameException

定义的数据包超过预定义大小异常类

(8)CorruptedFrameException

定义的数据包损坏异常类

3.frame包应用demo

解决分包问题,通常配置MyPipelineFactory中设置,示例如下:publicclassMyPipelineFactoryimplementsChannelPipelineFactory{[/b][/b]@Override[/b]publicChannelPipelinegetPipeline()throwsException{[/b]ChannelPipelinepipeline=Channels.pipeline();[/b]pipeline.addLast("decoder",newLengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));[/b]pipeline.addLast("encoder",newLengthFieldPrepender(4,false));[/b]pipeline.addLast("handler",newMyHandler());[/b]returnpipeline;[/b]}[/b][/b]}[/b][/b][/b]在客户端设置[/b]pipeline.addLast("encoder",newLengthFieldPrepender(4,false));[/b]pipeline.addLast("handler",newMyHandler());[/b][/b]前四个字节表示真实的发送的数据长度[/b]Length[/b],编码时会自动加上;[/b][/b][/b]在服务器端设置[/b]pipeline.addLast("decoder",newLengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));[/b]真实数据最大字节数为[/b]Integer.MAX_VALUE[/b],解码时自动去掉前面四个字节[/b][/b][/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: