TCP粘包与UDP数据报边界
TCP粘包与UDP数据报边界
UDP丢包是因为数据包在传送过程中丢失了 而TCP是基于流式的发送 并且存在丢包重发机制 TCP是可靠连接而UDP是不可靠的这个我就不多说了
关于TCP的粘包 正是由于TCP是流式传送的 也就是连接建立后可以一直不停的发送 并没有明确的边界定义 而你用UDP发送的时候 是可以按照一个一个数据包去发送的 一个数据包就是一个明确的边界
而TCP并没有数据包的概念 是完全流式的 他会开辟一个缓冲区 发送端往其中写入数据 每过一段时间就发送出去 然后接收端接收到这些数据 但是并不是说我发送了一次数据就肯定发送出去了 数据会在缓冲区中 有可能后续发送的数据和之前发送的数据同时存在缓冲区中随后一起发送 这就是粘包的一种形式 接收端也有产生粘包的情况 如果应用程序没有及时处理缓冲区中的数据 那么后续到达的数据会继续存放到缓冲区中 也就是2次接收的数据同时存在缓冲区中 下次取缓冲区的时候就会取出2次粘包后的数据 这是粘包的另外一种形式 还有其他许多形式 比如填充缓冲区到一半缓冲区满了直接发送了 但是其实那个包还没填充完全 这个就是不完整的粘包了 剩余数据会在下次发送的时候补上
关于解决方法 如果你是连续的整个数据流 比如发送文件 那么完全不考虑粘包也无所谓 因为可以建立连接后发送 发送完毕后断开连接 整个数据流就是整个一个文件 无论数据从那里切开都无所谓 整个拼接后依旧是整个一个文件的数据
如果你发送的数据是多次通信 比如把一个目录下所有的文件名都发送过去 那么就不能当作一个整体发送了 必须对他们划分边界 有一个很简单的处理方法 就是采用"数据长度+实际数据"的格式来发送数据 这个"数据长度"的格式是固定宽度的 比如4字节 可以表示0~4GB的宽度了 足够用了 这个宽度说明了后续实际数据的宽度 这样你就可以把粘包后的数据按照正确的宽度取出来了
每次都是取出4字节 随后按照正确的宽度取出后续部分的就OK了
如果你的所有数据都是固定宽度的 比如不停的发送温度数据 每个都是1字节 那么宽度已知了 每次你都取出一个1字节就OK了 所以就不用发送宽度数据了
当然你也可以按照建立连接断开连接来划分边界 每次发送数据都打开关闭一次连接 不过对于频繁的小数据量是不可取的做法 因为开销太大 建立连接和关闭连接也是需要耗费网络流量的
总而言之 粘包的情况是无法绝对避免的 因为网络环境是很复杂的 依赖发送和接收缓冲区的控制是不能保证100%的 只要在发送的数据中说明数据的宽度随后在接收部分按照这个宽度拆开就OK了 宽度全都是统一的已知宽度的情况下拆开更加容易 连在发送端填入宽度数据都可以省去了