Tcp是一个流的协议,一个完整的包可能会被Tcp拆成多个包进行发送,也可能把一个小的包封装成一个大的数据包发送,这就是所谓的粘包和拆包问题
粘包、拆包出现的原因:
在流传输中出现,UDP不会出现粘包,因为它有消息边界
1、要发送的数据大于TCP发送缓冲区剩余空间,需要被拆包
2、待发送的数据大于MSS(最大报文长度),TCP在传输前将进行拆包
3、要发送的数据小于TCP发送的缓冲区大小,TCP将多次写入的缓冲区一次发送出去,就会出现粘包
4、接受数据端的应用层没有及时读取TCP接受缓冲区的数据,将发生粘包
粘包、拆包解决办法:
1、消息定长,例如每个报文的大小固定长度200个字节,如果不够 ,空位补空格;
2、在包尾增加特殊符号分隔符
3、将消息分为消息头和消息体,消息头中包含表示消息总长度的字段,通常设计思路是消息头的第一个字段用int来表示消息的总长度
4、更复杂的应用层协议
netty对以上4种应用做了抽象,提供了4种解码器:
LineBasedFrameDecoder:依次编译bytebuf中的可读字符,判断看是否有"\n"或者"\r\n",如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行,它是以换行符为结束标志的解码器,支持携带结束符或者不携带结束符两种解码方式,同时支持单行的最大长度,如果连续读取到最大长度后,仍然没有发现换行符,就会抛出异常,同时忽略掉之前读到的异常码流
FixedLengthFrameDecoder:固定长度解码器,它能按照指定的长度对消息进行自动解码,开发者不需要考虑TCP的粘包等问题,利用FixedLengthFrameDecoder解码,无论一次性接受到多少数据,他都会按照构造函数中设置的长度进行解码,如果是半包消息,FixedLengthFrameDecoder会缓存半包消息并等待下一个包,到达后进行拼包,直到读取完整的包
DelimiterBasedFrameDecoder:自定义的分隔符解码,构造函数的第一个参数表示单个消息的最大长度,当达到该长度后仍然没有查到分隔符,就抛出TooLongFrameException异常,防止由于异常码流缺失分隔符号导致的内存溢出
LengthFieldBasedFrameDecoder:通过固定长度来区分整包消息,消息定长,报文大小固定长度,不够空格补全,发送和接受方遵循相同的约定,这样即使粘包了通过接收方编程实现获取定长报文也能区分。
·
原文地址:https://www.cnblogs.com/cherish010/p/9042626.html