什么是TCP粘包?
TCP粘包就是发送方发送的若干个数据到达接受方时粘成了一个包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
举个例子:
假如发送方发送了两个数据包A和B。其中A的消息内容为hello
, B的消息内容为world
。那么由于TCP是流式协议。接受方收到的数据可能为AB : helloworld
。此时AB两个TCP包就粘在了一起。
如何解决粘包问题
由于TCP是面向字节流的协议,因此用户层协议是需要将一个个包拆开的。比如常见的HTTP协议,其就不用担心粘包和拆包的问题。但是对于自己实现一个TCP server的话,需要在应用层处理该问题。好在,前人已经给出了很多相关的经验去处理该问题。下面给出三种常见的方式,这也是Netty的三种decode方式。
固定包长度
以本文的AB粘包为例。假设我们设计一个TCP server,第一种解决粘包问题的方法就是 固定每个包长为5字节。发送方和接受方约定好。这样接受方无论接受到的是 he+lloworld
还是 hellow+orld
, 反正接受方就按5字节解析就完事了。解析出来的就是hello
和 world
指定分割符
比如 我们指定两个不同语义包的分割符为 \r\n
。 那么 接受方接受到的消息可能是 hello\r\nwo
和 rld\r\n
。 最终我们接受方按照\r\n
进行split 就好了。就能得到不同语义的包。
固定长度请求头
第三种方式 是 采用请求头+请求体的方式。其中请求头是固定字节的,比如4个字节。
如包结构为:
header:content
5 : hello
这样接受方每次先读取请求头的四个字节,得到请求体的长度,然后再读取请求体长度,这样就得到一个语义包的内容了。
总结
TCP粘包一般在设计私有应用层协议时需要注意。如果采用流行的HTTP或者其他RPC协议时,其内部网络框架会帮使用者处理好该问题。不过这对于理解网络传输本身还是有益的。