TCP协议是面向流的协议,是流式的,没有业务上的分段,只会根据当前套接字缓冲区的情况进行拆包或者粘包:
发送端的字节流都会先传入缓冲区,再通过网络传入到接收端的缓冲区中,最终由接收端获取。
因为TCP会根据缓冲区的实际情况进行包的划分,在业务上认为,有的包被拆分成多个包进行发送,也可能多个晓小的包封装成一个大的包发送,这就是TCP的粘包或者拆包。
假设客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次读取到字节数是不确定的,故可能存在以下几种情况: 1. 服务端分两次读取到两个独立的数据包,分别是D1和D2,没有粘包和拆包。 2. 服务端一次接收到了两个数据包,D1和D2粘在一起,发生粘包。 3. 服务端分两次读取到数据包,第一次读取到了完整的D1包和D2包的部分内容,第二次读取到了D2包的剩余内容,发生拆包。 4. 服务端分两次读取到数据包,第一次读取到部分D1包,第二次读取到剩余的D1包和全部的D2包。
当TCP缓存再小一点的话,会把D1和D2分别拆成多个包发送。
因为TCP只负责数据发送,并不处理业务上的数据,所以只能在上层应用协议栈解决,目前的解决方案归纳: 1. 消息定长,每个报文的大小固定,如果数据不够,空位补空格。 2. 在包的尾部加回车换行符标识。 3. 将消息分为消息头与消息体,消息头中包含消息总长度。 4. 设计更复杂的协议。
Netty提供了多种默认的编码器解决粘包和拆包:
基于回车换行符的解码器,当遇到