网络基础:TCP协议-粘包问题

面向字节流

创建一个socket的,不仅仅只是申请一个文件描述符,并且还开辟一片发送缓冲区及接收缓冲区。在调用write进行写数据时,先写入发送缓冲区当中,如果数据较大,那么TCP进行分包发送。如果数据较小,那么就现在发送缓冲区内部等待,等到了合适的时候再发出。在接收数据时,首先从网卡驱动程序中将数据读至接收缓冲区,接着调用read进行读数据。由于TCP既有发送缓冲区又有接收缓冲区,所以write与read并不冲突,可同时进行,这个就叫做全双工。
在进行读写的时候,不用一次性读完或写完,可以分批来。这也是面向字节流的好处。

粘包问题

我们都知道TCP属于传输层的协议,传输层除了有TCP协议外还有UDP协议。那么UDP是否会发生粘包或拆包的现象呢?答案是不会。UDP是基于报文发送的,从UDP的帧结构可以看出,在UDP首部采用了16bit来指示UDP数据报文的长度,因此在应用层能很好的将不同的数据报文区分开,从而避免粘包和拆包的问题。而TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界;另外从TCP的帧结构也可以看出,在TCP的首部没有表示数据长度的字段,基于上面两点,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能。

粘包问题的形式

在前面讲到TCP面向字节流,并且在发送时候,先写入到发送缓冲区内部。但是在发送缓冲区内部不一定发送,如果数据过小会等待接下来的数据。如果过大就分包,这就造成了粘包的问题。
具体形式如下:
这里写图片描述
这种情况属于正常情况,不会发生粘包问题。

这里写图片描述
这种情况是因为data1到达接收端接收缓冲区后未被处理,此时data2也到达。这样data1与data2粘包。

这里写图片描述
这种情况是因为data1的数据太大,发送缓冲区一次发不完,于是拆包并分包。分两次发送,第一次发送成功,第二次发送时data2也在发送缓冲区,此时data1的后面部分与data2发生粘包。

这里写图片描述
这种情况是因为data1数据过短,在发送缓冲区等待,此时data2写入发送缓冲区,发送缓冲区满了,导致data2后半部分分包。这样data1与data2的前半部分发生粘包。

粘包产生的常见原因

发生TCP粘包或拆包有很多原因,列出常见原因:

  1. 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。
  2. 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。
  3. 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。
  4. 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。

粘包的解决方法

解决粘包问题的核心就是明确两个包的界限!!!

解决方式:

  1. 在接收端接收的时候采用定长的方式接收,调用read读取时每次都是固定的长度进行读取。
  2. 人为的在数据包报头添加数据包长度。
  3. 发送端在数据包边界设置明确的分隔符,如特殊符号等。

欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!

猜你喜欢

转载自blog.csdn.net/liuchenxia8/article/details/80435525