粘包:通俗的讲,在我们买包子的时候,我们可以看到蒸笼中,每个包子之间都隔开了空间,或者是用纸把每个包子都隔离开了,不让它们粘在一起。如果让两个包子之间无缝隙的在粘在一起。当你买包子时,老板把一个包子装起来,另个一个包子的皮就会粘到你的这个包子来。两个包子都多了点,另一个少了点。包子不完整了,外观不完美了。
同样的,在我们TCP面向字节流传输过程中,我们也会遇到这样的问题。
粘包中的“包”指的是应用层数据包。
当我们要传输数据的时候,传输层中会把数据分成有序列号的字段,并存放在发送缓冲区中。根据TCP协议的机制,可靠的发送给了对端接受方。
接受方接收到了数据,并存放在接受缓存区中。每一个字段都是有序号的,但是因为每时每刻的网络复杂程度不一样,所以每次接受到的字段长度都有所不同。
那么在我们的接受方主机是如果每次都按照一定的长度去读取接受缓存区中的数据时,就会多读了下一个字段中的数据,或者少读了该字段中的额数据。——这就是粘包问题。(不知道从那个部分开始到那个部分是一个完整的数据包)
解决粘包问题:
1.我们可以使用明确的分隔符作为每个数据包的边界(应用层协议,只要保证分隔符不和正文冲突)
2.对于定长的包,保证每次都按照固定的大小读取数据就行了
3.对与变长的包,可以在包头的位置,约定一个包总长度的字段,从而知道了包的结束位置
对比面向数据报:
我们知道UDP协议是面向数据报的形式传输数据的。
UDP协议,如果还没有上层交付数据,UDP的报文长度任然在,同时是一个一个把数据交付给应用层,就是有很明确的数据边界。
站在应用层的角度看,使用UDP协议传输数据时,要么对方完整的接受到UDP报文,要么不收。(不会出现子接受一半的情况)