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

本文介绍了TCP/IP数据包处理中的关键技术,包括FrameDecoder的作用及其实现原理,FixedLengthFrameDecoder和DelimiterBasedFrameDecoder的具体应用。文章详细解释了如何解决数据包碎片问题,以及如何根据固定长度或分隔符进行数据包重组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码地址: GitHub

1.  frame包整体功能描述

此包主要作用于对TCP/IP数据包的分包和包重组,常用于数据的流传输,是扩展的解码器。

包目录结构如下:

netty 数据分包、组包、粘包处理机制(一) - 断鸿零雁 - 断鸿零雁的博客

2.包中各类功能详解

(1)  FrameDecoder

抽象类,将ChannelBuffers中的二进制数据转换成有意义的数据帧(frame)对象,一般不直接调用,提供给此包中的FixedLengthFrameDecoder类、DelimiterBasedFrameDecoder类和LengthFieldBasedFrameDecoder类使用,也可以提供给其他类使用(暂不探讨);

在数据传输中,我们发送的数据包如下所示

115540_IC6Y_3101476.png

而实际接收的包的格式为:

115557_dtDl_3101476.png

产生的原因为:数据在传输过程中,产生数据包碎片(TCP/IP数据传输时大数据包无法一次传输,被拆分成小数据包,小数据包即为数据包碎片),这就造成了实际接收的数据包和发送的数据包不一致的情况。

而通过FrameDecoder即可实现对上述接收到的数据包的整理,重新还原成如下格式:

115639_5To3_3101476.png

如下是一个自定义的Decoder类

public class MyFrameDecoder extends FrameDecoder {
         @Override
   protected Object decode(ChannelHandlerContext ctx,

                           channel,

                           ChannelBuffer buf) throws Exception {

     // Make sure if the length field was received.
     if (buf.readableBytes() < 4) {
        // The length field was not received yet - return null.
        // This method will be invoked again when more packets are
        // received and appended to the buffer.
        return null;
     }

     // The length field is in the buffer.
     // Mark the current buffer position before reading the length field
     // because the whole frame might not be in the buffer yet.
     // We will reset the buffer position to the marked position if
     // there's not enough bytes in the buffer.
     buf.markReaderIndex();
     // Read the length field
     int length = buf.readInt();
     // Make sure if there's enough bytes in the buffer.
     if (buf.readableBytes() < length) {
        // The whole bytes were not received yet - return null.
        // This method will be invoked again when more packets are
        // received and appended to the buffer.
        // Reset to the marked position to read the length field again
        // next time.
        buf.resetReaderIndex();
        return null;
     }
     // There's enough bytes in the buffer. Read it.
     ChannelBuffer frame = buf.readBytes(length);
     // Successfully decoded a frame.  Return the decoded frame.
     return frame;
   }
 }

此时,我们无需关注数据包是如何重组的,只需要做简单的验证(按照一个包验证)就可以了,FrameDecoder内部实现了组包的机制,不过,此时,需在数据的最前面封装整个数据的长度,示例中数据长度占了四个字节,即前四个字节是数据长度,后面的才是真实的数据。

(2)  FixedLengthFrameDecoder

FixedLengthFrameDecoder主要是将诸如

120337_Uyoc_3101476.png

此类的数据包按照指定的frame长度重新组包,比如确定长度为3,则组包为

120356_oRr9_3101476.png

构造方法为:new FixedLengthFrameDecoder(int frameLength);

frameLength即修正后的帧长度

另一个构造方法为new FixedLengthFrameDecoder(int frameLength, boolean allocateFullBuffer); allocateFullBuffer如果为真,则表示初始化的ChannelBuffer大小为frameLength。

(3)  Delimiters

分隔符类,DelimiterBasedFrameDecoder类的辅助类。

对Flash XML的socket通信采用nulDelimiter()方法,对于一般的文本采用lineDelimiter()方法

(4)  DelimiterBasedFrameDecoder

对接收到的ChannelBuffers按照指定的分隔符Delimiter分隔,分隔符可以是一个或者多个

如将以下数据包按照“\n”分隔:

120624_lsmg_3101476.png

即为:

120640_zjvc_3101476.png

而如果按照“\r\n”分隔,则为:

120704_rQwa_3101476.png

对于DelimiterBasedFrameDecoder中的构造方法,其中一些参数说明:

  1. maxFrameLength:解码的帧的最大长度
  2. stripDelimiter:解码时是否去掉分隔符
  3. failFast:为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常,为false,读取完整个帧再报异常
  4. delimiter:分隔符

 

 

 

转载于:https://my.oschina.net/LucasZhu/blog/1620100

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值