• 面试冲刺:54---MTU是什么?IP分片是什么?MSS是什么?TCP和UDP会分片吗?它们的关系是什么?


    文章介绍之前先介绍几个概念

    • 应用层:传输的数据单位为“报文”
    • 运输层:
      • TCP:传输的数据单位为“报文段”
      • UDP:传输的数据单位为“用户数据报”‘’
    • IP层/网络层:传输的数据单位为“分组/包”,就是将运输层的内容封装为“分组/包”,并通过路由转发
    • 数据链路层:传输的数据单位为“帧”
    • 物理层:传输的数据单位为“比特”

    一、什么是MTU?

    • 在数据链路层中用MTU(Maximum Transmission Unit,最大传输单元)来限制所能传输的数据包大小
    • MTU是指一次传送的数据最大长度,不包括数据链路层数据帧的帧头。如以太网的MTU为1500字节,实际上数据帧的最大长度为1514字节,其中以太网数据帧的帧头为14字节

    二、IP分片

    • 当发送的IP数据包的大小超过了MTU时,IP层就需要对数据进行分片,否则数据将无法发送成功
    • IP分片是将一个IP划分成多个IP分片,每一个分片都是一个独立的IP数据报。在IP数据报的头部有数据报ID和分片标识符,用于将同一个IP数据报的不同分片重新组合。由于因特网上的各个网段的MTU不同,IP数据报可能会在路由过程中被路由器重新分片。在一条路由路径上最小的MTU叫做路径MT
    • 如果IP数据报在头部设置了不可分片标志,则路由器丢弃大于本段MTU的IP数据报,并向源主机发送ICMP出错报文(需要分片,但是设置了禁止分片的标志位)
    • IP层是没有超时重传机制的,如果IP层对一个数据包进行了分片,只要有一个分片丢失了,只能依赖于传输层进行重传,结果是所有的分片都要重传一遍,这个代价有点大;公网传输,需要经过多个网络设备,IP分片容易造成丢包
    • 由此可见,IP分片会大大降低传输层传送数据的成功率,所以我们要避免IP分片

    三、TCP的MSS选项

    • TCP会尽量避免IP分片的发生,因为在三次握手的过程中双方会相互通知对方自己的MSS(Maximum Segment Size,最大段大小)
    • MSS是TCP报文头部中的一个选项,如下图所示:

    • 最大段大小是指TCP协议所允许的从对方接收到的最大报文段,因此这也是通信对方在发送数据时能够使用的最大报文
    • 最大段大小只记录TCP数据的字节数而不包括其他相关的TCP与IP头部
    • MSS通常设置成:MSS=MTU-TCP头部大小-IP头部大小(这里的MTU可能指的是本地MTU,因为TCP协议没有发现路径MTU的机制。而且这个MSS是可以本地设置的)
    • 注意,TCP两端以segment的形式交换数据,但TCP本质是没有分段的,它具有流的特点。TCP的实现从内核的套接口发送缓冲区中取出MSS大小的数据,安上TCP和IP头然后交由下层协议实现处理
    • MSS的详细介绍可以参阅:TCP/IP卷一:66---TCP连接管理之(TCP选项(最大段大小/选择确认/窗口缩放/时间戳/用户超时/认证选项))_董哥的黑板报的博客-CSDN博客

    四、TCP的分片

    TCP接收缓冲区、TCP发送缓冲区

    • TCP在通信的时候,通信的端点各自都有自己的"TCP接收缓冲区"和"tcp发送缓冲区"
    • TCP通信的流程如下:
      • 假设A给B发送数据,A先调用send()函数发送数据,此时数据会先放到"tcp发送缓冲区"当中,然后再由系统传送到B的"TCP接收缓冲区"中,此时B调用recv()读取数据时,实际上是从"TCP接收缓冲区"中读取到数据的
      • B给A发送数据的原理也是一样的

    • 备注:
      • SO_RCVBUF、SO_SNDBUF套接字选项:Linux系统环境编程中可以使用setsockopt()函数调用这两个参数来分别设置TCP的"接收缓冲区"大小和"发送缓冲区"大小
      • 当然,你也可以自己在自己的代码中定义一个数组或者可以存储数据的容易来实现"应用层的缓冲区",这个就不想详细介绍了

    从上面的分析我们可以看出:

    • TCP发送数据时,把数据发送到"发送缓冲区",然后由系统将这些数据组织成IP数据报,然后进一步在网络中进行传输。
    • TCP三次握手的时候,在SYN报文中指定一个MSS值,MSS=MTU-TCP头部大小-IP头部大小(所以MSS肯定比MTU小)
    • 当TCP发出去的报文超出MSS大小的时候,TCP层的数据会切分为MSS的大小,这样的话就保证IP数据包不会在IP层进行分片了

    五、UDP的分片

    • 没有UDP分片的概念,其只是把数据传递给下层的IP层去传输的
    • 但是UDP没有缓冲区的概念,因为UDP本身就是不可靠传输的,所以UDP发送数据的时候,直接就是把所有的数据发送出去,然后由IP层进行路由发送,所以当UDP的数据包过大的时候(超过MTU的大小),IP层就会进行分片

    UDP的分包与组包

    • 因为UDP一次性的把所有数据直接发送出去,如果IP数据包过大(大于MTU),那么IP就会进行分片了,只要一个分片丢失,那么就需要重传所有的分片数据,因此这种消耗是比较大的
    • 所以在应用层的代码中,通常我们需要进行UDP的组包与分包,主要的思想就是封装自己的UDP数据格式,在调用sendto的时候发送指定格式内容的数据,对端调用recvfrom()接收数据的时候也接收指定格式内容的数据
    • 具体可以参阅:UDP分包与组包_董哥的黑板报的博客-CSDN博客_udp分包

    EMSGSIZE错误

    • UDP套接口虽然没有缓冲区,但是它有发送缓冲区大小,不过它仅仅是写到套接口的UDP数据报大小的上限。如果应用进程写一个大于套接口发送缓冲区大小的数据,内核将返回一个EMSGSIZE的错误
  • 相关阅读:
    【C++进阶】map和set——中篇(AVL树的学习)
    线程方法join/join(timeout)源码分析
    Matlab初识:什么是Matlab?它的历史、发展和应用领域
    asp.net饭店订餐管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio计算机设计定制
    学习笔记:机器学习优化算法之牛顿法、拟牛顿法
    vi编辑器:-vi的使用方法的记录
    【rbac简介】
    2020年五一杯数学建模C题饲料混合加工问题解题全过程文档及程序
    ZYNQ linux调试LCD7789
    基于MindSpore的llama微调在OpenI平台上运行
  • 原文地址:https://blog.csdn.net/qq_41453285/article/details/108035788