面向网络编程,会遇到数据接收过程中数据质量太差问题,很可能是TCP传输过程中数据拆解和封装过程及性能导致,这涉及到tcp报文的粘包与拆包,我们今天讲粘包和拆包的概念。
现象
tcp作为面向有连接、字节流的传输层协议,每次发送的一个业务报文都无固定大小边界,接收端应用层的一次读取操作并不能识别到拿到的数据是发送端的一个业务报文还是半个或者部分报文。以微信发消息场景为例,你连续向对方发送两个消息报文Data1和Data2,Data1只是一句话,Data2文字就要多很多,发送过程可能会发生以下三种情况:
- 服务端刚好用了2次从网络读取数据,并且第一次刚好全部数据都是Data1,第二次刚好全部数据都是Data2.
- 服务端第一次读取数据时,读到Data1的全部数据和Data2的首部部分数据。这个就叫做粘包现象。
- 因为网络控制原因,发送端Data2报文被发送端拆成Data2_0、Data2_1、Data2_2.....服务端一次不会读取到Data2消息报文的全部数据,需要多次才能完成Data2的读取。这个就叫做拆包现象。
TCP帧
是一个物理级别的格式,根据当前网络情况会自动调整帧大小,大小不固定,是业务报文传输的载体,我们从客户端传到服务器的业务报文就是通过这样的一帧、一帧载体传到服务器端的。
粘包原因
1. 是为了减少网络中小分组的数目,尽可能避免网络拥塞的出现而采用Nagle算法。采用Nagle算法时发送端会先将第一个小分组发送出去,而将后面到达的小分组都缓存起来而不立即发送,直到收到接收端对前一个小分组的ACK确认、或当前字符属于紧急数据,或者积攒到了一定数量的小分组等多种情况才将其组成一个较大的分组发送出去。
2. 发送端需要等缓冲区满才发送出去,造成粘包。
3.接收方不及时接收缓冲区的包,造成多个包堆积在一起。
拆包原因
1、tcp传送的端mss大小限制;链路层也有MTU大小限制,如果数据包大于MTU时要在IP层进行分片,导致报文分割。
2、tcp的流量控制和拥塞控制,也可能导致粘包、半包。
3、应用层设定的缓冲区不足以容纳报文,读取时只读取了一部分。
解决方案
很多IO网络框架都已提供粘包、拆包的支持,如Netty、Mina等。
1、禁用Nagle算法,这种方法虽然能一定程度上解决TCP粘包,但是并不能完全解决问题,反而可能降低TCP传输效率。而且接收方也是可能造成粘包的原因,这种方法只是发送方有效。所以,这并不是一种理想的方法。
2、格式化报文:每个报文有固定的格式如尾部包含结束符,但在选择结束符时一定不能在报文内部。
3、设定报文头:在每个报文前添加一个报文头,头部含有长度、类型等信息。读取时,根据报文头的长度来读取报文,从而判断每个报文的开始和结束。
我们在Netty编程章节会重点讲Netty常用的对各种报文格式的拆包、粘包方案。
2787

被折叠的 条评论
为什么被折叠?



