LengthFieldBasedFrameDecoder()解决Tcp粘包/半包问题

背景:最近使用Netty来做项目,过程中与服务器通信出现了Tcp协议的沾包/半包问题。其中,我还被大端小端给坑了一次,特写此文记录一下自己的解决办法。

说明:一般来说,使用Tcp进行通信会出现沾包/半包现象,这是因为Tcp协议是流式协议,没有明确的消息帧的分界线。

TCP消息格式

Socket消息格式
图片解读:一个消息帧(frame)由 消息头(Head) 和 消息体(Body) 组成。其中,消息头总长度由长度域(Length)和一个 其他(others)组成,其总长度固定。

Length:长度域,一般代表消息体(body)的字节数,也就是长度,一般是大端模式(指低字节存放长度的高位)。
others: 消息头的其他组成部分,一般用于区分消息的用途。这个根据项目需求来设计。

以上就是我使用的消息帧格式,但是如何确保每次接收到的消息帧都是完整的呢,这就要用到我们的主角 LengthFieldBasedFrameDecoder() 解码。


LengthFieldBasedFrameDecoder() 解码器

简介:该解码器是Netty提供给开发者的解码器之一,其使用场景是用于区分本文中提供的这种消息帧格式。下图是其多个构造函数

在这里插入图片描述
其参数比较多,我们一一介绍。

参数作用
@NotNull ByteOrder byteOrder这是一个隐藏的参数,用于表示,长度域的大小端模式,如果不填写,默认为大端模式。比如你的长度域是大端模式(低字节放置int的高位),则该参数设置为ByteOrder.BIG_ENDIAN;反之,小端模式设置为,ByteOrder.LITTLE.ENDIAN。这里需要注意的是,若使用该参数,则必须使用图中参数最多的构造函数
int maxFrameLength代表每一个消息帧的最大支持长度,根据自己项目需要设计,可设置大一些,设置小了,如果消息总长度超出这个值,Netty会报错
int lengthFieldOffset长度域的起始位置下标,比如Head的头四个字节代表了body的长度,那么长度域就是从下标为0的位置开始,此时该值为0
int lengthFieldLength长度域的长度,也就是说长度域占用了几个字节,比如我占用了4个字节表示body,那么,此时为4
int lengthAdjustment该参数简单来说,就是指Head里除了长度域还剩下几位,比如我的Head由Length和others组成,Length占用4个字节,others占用10个字节,那么这个参数就是10,这个参数的作用就是告诉Netty你的Head的长度是多少
int initialBytesToStrip这个参数是指,解码器解码后,你需要多少数据,就是指舍弃的字节的数量,这里是从前到后舍弃的。比如说,解码后我只想要整个消息帧的body段,那么你就要舍弃掉head的长度,也就说这个数就填写head + others共占用的字节数量,在本文中,我填写的是14
boolean failFast默认为True。这个参数为True:当Netty监测到接收到的字节数量大于maxFrameLength时,立马thrown处一个Exception。 设置为False:当Netty监测到接收到的字节数量大于maxFrameLength后,等到把全部数量接收完,再thrown出一个Exception,这里一般我们设置为true即可

比如说,我使用的协议是, Head长度为14个字节,其中长度域从下标0开始,占用4个字节;others从下标4开始,占用10个字节。剩下的就是body。而且我的长度域是小端模式,另外解码后我不想舍弃掉任何字节。那么我们的参数这样设置即可。

private final LengthFieldBasedFrameDecoder FRAME_DECODER =
        new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN,1024,0,4,32,0,true);

以上文章,如有纰漏或错误,还望指正。
如若转载,请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity实现Socket通讯时,常常会遇到TCP粘包和拆包的问题。下面我将介绍在Unity中如何解决这些问题TCP粘包是指在传输过程中,由于数据缓冲区的限制,多个小的数据包可能会被合并成一个大的数据包,导致数据的解析和处理出现问题。为了解决这个问题,可以通过以下两种方式来处理。 第一种方式是定长包头+包体的设计。即在数据包前面添加一个固定长度的包头,包头中包含了包体的长度信息。接收方在接收数据时,首先读取包头的长度信息,然后再根据长度信息读取相应长度的数据进行解析和处理。 第二种方式是使用特殊的字符序列作为包的分隔符。例如,在每个数据包的末尾添加一个换行符或其他不常用的字符作为分隔符。接收方在接收数据时,通过查找这个分隔符来确定包的结束位置,然后对数据进行解析和处理。 TCP拆包是指在传输过程中,一个大的数据包可能会被拆分成多个小的数据包,导致数据的解析和处理出现问题。为了解决这个问题,可以通过以下方式来处理。 可以在接收方使用缓冲区来接收数据,并且设置一个最大接收长度。当接收到的数据长度小于最大接收长度时,将数据放入缓冲区中,并在缓冲区中进行数据的拼接。当接收到的数据长度大于等于最大接收长度时,对缓冲区中的数据进行解析和处理,并清空缓冲区。 以上是Unity实现Socket通讯时解决TCP粘包和拆包问题的方法。希望对你有帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值