粘包:比如客户端发送了第一个数据包内容为abc,然后又发送了第二个数据包为bcd,服务端接收到了数据,内容是abcbcd,对于接收数据的服务端来说,是无法区分哪些内容是哪个数据包的,也无法区分客户端到底发送了几个数据包。当然了也许不止2个数据包粘在一块。这样的情况就称为粘包。
粘包
拆包:比如客户端发送了2个数据包,服务端也收到了2个数据包,但是这2个数据包属于同一条消息,因为消息太大等原因,被拆成了几个数据包发送。这样的情况就称为拆包。
拆包
看到这里你可能会问,为什么会出现TCP的拆包和粘包,而没听说过UDP会出现拆包和粘包呢?它们不都是传输层协议吗?
其实UDP协议真的没有拆包和粘包的问题,只有TCP协议有,为什么呢?因为TCP是流式协议,每次发送数据都会有一个固定的大小,为了提高TCP传输的性能,发送端会把数据发送到一个缓冲区,当缓冲区满了后,再把缓冲去中的数据发送到接收端,同样的接收端也是同样的机制来接收数据。
因此当发送端需要发送的内容大于缓冲区的大小,就会发生拆包的现象,当发送端的内容太小,就容易发生粘包的现象,导致不同的消息一起发送给接收方。当接收方不能及时获取消息时也会导致粘包的现象发生。
除了拆包和粘包还有一个词语叫做半包,那么什么是半包呢?
半包就是发送的数据包包含了整个消息的一部分,这样的数据包就叫做半包。
那么为什么UDP协议不会发生拆包和粘包呢?因为UDP协议每个消息是相互独立的,发送方发送一次,和接收方接收一次是一一对应的,比如,发送方发送了abc,然后又发送了bcd,那么接收方接收一次内容是abc,接收方再接收一次才是bcd,因此UDP协议不会出现拆包和粘包的问题。
我们已经了解了粘包和拆包的发生的原因,那么有什么解决方案呢?常用的方案又是哪些呢?
常用的解决方法有四种:
1.消息是定长的,报文长度固定,比如设定一个报文长度为300,如果实际内容不够300就用空格占位。
2.在报文的尾部添加特殊的分隔符,接收方通过特殊的分隔符来区分报文的结尾。
3.将消息分为消息头和消息尾,在消息的头部使用标识表名信息的总长度。
4.使用更加复杂的自定义的应用层协议。