TCP之”粘包与拆包“

700 阅读2分钟

当我看到粘包和拆包其实是有些迷糊的,这便是我面向百度学习的开始。于是发现了一个有意思点,就是我标题上加的引号了,今天在此记录下来


什么是包

在我搜索时发现大家说的包有两种

  • 一是指应用层数据,应用层调用send方法发送的数据,暂且称之为应用层报文
  • 二是指传输层报文,应用层的数据会被传输层封装,报文首部和报文数据,合起来就是一个包了

粘包现象

这也有两种情况

image.png

  • 一是指多个传输层的包被同一个缓冲区读取了,就是发送方send了连续多个应用层报文,而接收方只recv了一次就读取了所有报文。
    • 原因 其实这只是一个报文边界问题,tcp明确的说明。它负责把你的数据按序以流的形式发送到对方,且保证不会出错,但是需要应用本身解析字节流(实现stream2datagram)
    • 解决
      • 法一 在数据边界写入特殊分割字符
      • 法二 在报头写入报文长度,事实上ip和tcp都是这么干的
      • 法三 固定报文长度,多余填充0
  • 二是指是tcp的实现,为了解决大量小报文场景下包头比负载大,导致传输性价比太低的问题,专门设计的Nagle算法。Nagle的算法通常会在TCP程序里添加两行代码,在未确认数据发送的时候让发送器把数据送到缓存里。任何数据随后继续直到得到明显的数据确认或者直到攒到了一定数量的数据了再发包
    • 解决 可以通过关闭Nagle算法
    • Nagle算法的规则(可参考tcp_output.c文件里tcp_nagle_check函数注释):
      • (1)如果包长度达到MSS,则允许发送;
      • (2)如果该包含有FIN,则允许发送;
      • (3)设置了TCP_NODELAY选项,则允许发送;
      • (4)未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
      • (5)上述条件都未满足,但发生了超时(一般为200ms),则立即发送。

拆包现象

  • 一是指写入的数据大于接收方缓冲区的大小,应用层需要读取多次
  • 二是指进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP首部长度>MSS的时候将发生拆包