【计网笔记】一起重温计网咯 | TCP协议的粘包/拆包问题

一起重温计网咯 | TCP协议的粘包/拆包问题


如果觉得对你有帮助,能否点个赞或关个注,以示鼓励笔者呢?!博客目录 | 先点这里

  • 前提概要
    • MTU,MSS
    • IP分片和TCP分段
    • TCP缓冲区
  • TCP粘包/拆包
    • 什么是粘包/拆包问题?
    • 为什么会产生粘包/拆包问题?
    • 粘包/拆包的解决方案

前提概要


MTU,MSS

在学习IP分片和TCP分段之前,我们先来学习一下MTU和MSS的概念

  • MTU
    Maxitum Transmission Unit 最大传输单元。 MTU典型的应用就是在IP分片中,MTU其实是数据链路层的最大传输单元,使用了不同的数据链路层,也会导致不同的MTU, 我们最常见的以太网数据链路方式的MTU是1500b
  • MSS
    Maxitum Segment Size 最大分段大小。 一般情况下,只有TCP类似协议才用的上MSS, TCP在传输大量数据的时候,只要数据大于MSS大小,就会进行TCP数据段的分段传输。MSS是传输层TCP连接一次可以发送的最大数据大小。
    在这里插入图片描述

MTU和MSS的关系:

  • MTU和MSS的关系一般如上图,我们数据链路层以以太网数据帧举例,以太网帧大小一般为1518b
  • MTU = 以太网帧 - 以太网帧首 - 以太网帧尾 = 1500b
  • MSS = MTU - IP首部 - TCP首部 = 1460b

IP分片和TCP分段

什么是IP分片?

  • 网络层就会涉及到IP分片(Fragment)的问题。一个IP数据报在以太网中传输,如果它的长度大于以太网帧的MTU,就要将数据进行分片,使得每片数据报的长度小于MTU,分批传输。
  • 分片传输的IP报因为各种原因是不一定按序到达的,既目的机器乱序接收,也由目的机器按序重组。因为IP首部中的 “片偏移” 字段可以判断一个IP数据报是否分片以及当前分片属于整个数据报的起始,中间还是末尾位置。
    在这里插入图片描述
    上图来源于网络

什么是TCP分段?

  • 我们知道TCP是以流动的方式传输数据,传输的最小单位为一个报文段(segment)。TCP Header中有个Options标识位,常见的标识为MSS,用于记录TCP段的最大分段大小,在以太网中,因为MTU一般为1500比特, 所以MSS = MTU - IP Header - TCP Header ,也就是1460比特
  • TCP在传送大量数据的时候,如果数据量大于MSS,那么数据段就会被分割成MSS大小进行传输。MSS是在三次握手的时候,在两端主机之间被计算得出的。两端的主机在发出建立连接的请求时,会在TCP首部写入MSS选项,告诉对方自己的接口能够适应MSS的大小。然后在两者之间选择一个较小值作为通讯双方的MSS
    在这里插入图片描述
    上图来源于网络

因为TCP协议中存在TCP分段的设计,所以从传输层到网络层的过程中,因为数据包是不可能超过MSS的长度,而MSS正常来说肯定是小于MTU的长度。所以,我们可以判断TCP协议基本上是不会发生IP分片,IP分片是相对UDP协议,ICMP等协议而言的。


TCP缓冲区
  • 通常所说的TCP收发缓冲区Socket收发缓冲区其实是一个东西,但这说法不完整正确,要取决于Socket是基于那种传输层协议,因为UDP也有缓冲区。
  • TCP为提高性能,发送端会将需要发送的数据发送到缓冲区,等待缓冲区满了之后,再将缓冲中的数据发送到接收方。同理,接收方也有缓冲区这样的机制,来接收数据
  • 如果没有缓冲区的话,那么要做到保证接收的数据是按顺序传输的,那么如果位于x序号之后的序号分组先到达目的主机的运输层的话必然丢弃,这样的话将在重传上花费很大的开销,所以一般如果有过大的序号达到接收端,那么会按照序号缓存起来等待之前的序号分许到达,然后一并交付到应用进程。
  • TCP缓冲区和窗口大小是相关的,我们知道窗口大小是在不断的变化的,可以理解为TCP缓冲区是窗口大小的最大值,而窗口大小是TCP缓冲区目前还能接收多少的数据

TCP粘包/拆包


什么是粘包/拆包问题?
  • 因为TCP协议是面向字节流的,所有数据在TCP层面看来,都只是一串无边界的流,即数据与数据之间是没有边界的。
  • 因为TCP协议中的数据是没有边界的流。如果用户对服务端发送了多个独立的数据,比如 "你好吗""你吃了吗" 两条数据,但是在TCP层面上看来,数据格式就是 "你好吗你吃了吗" ,所以我们就无法识别出哪里才算一个完整的数据包
  • 因为接收方不知道怎么才算一个完整的数据包,所以当接收方把 "你好吗你吃了吗" 数据流识别成 “你好”“吗你吃饭了吗”这就造成了拆包问题,把一个独立数据包的一部分拆分了成了两个包。如果我们的接收方把数据识别成了 "你好吗你吃了吗"那么这就造成了粘包问题,把两个独立数据粘在一起了。

为什么会产生粘包/拆包问题?

为什么拆包?

  • 应用程序写入的数据大于Socket缓冲区大小时,就会造成拆包
  • 待发送数据大于MSS最大TCP段长度,TCP在传输前将进行拆包

为什么粘包?

  • 应用程序写入数据小于Socket缓冲区的大小,多个独立的数据包被陆续或同时写入这个缓冲区,这就造成粘包
  • 如果接收方不及时读取Socket缓冲区中的数据,那么这可能将会导致发生粘包问题

所以我们可以知道TCP协议的粘包/拆包问题是TCP协议的特性导致的,主要是因为TCP分段以及TCP缓存区造成的,一定程度上可以说,是传输层导致的问题,而解决方案则是由应用层来解决。所以粘包/拆包问题也跟IP分片没有关系,只跟TCP分段有关系


粘包/拆包的解决方案
  • 使用带消息头的应用层协议。消息头存储消息开始标识及消息长度信息,服务端获取消息头的时候解析出消息长度,然后向后读取该长度的内容
  • 设置定长消息。应用层协议规定每个完整的数据包的定长,服务端每次读取既定长度的消息
  • 设置消息边界。类似http协议一样,每个完整的数据包后面都使用换行符或空格等符号表示

参考资料


  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值