哈喽大家好,我是咸鱼

《计算机网络那些事之 MTU 篇 》中,咸鱼跟大家介绍了 MTU 是指数据链路层能够传输的最大数据帧的大小

如果发送的数据大于 MTU,则就会进行分片操作(Fragment);如果小于 MTU,就会在实际数据内容后面添加填充数据(Padding),使得数据包总长度达到最小长度要求

TCP 因为是有连接的协议,连接在建立的时候就有 MSS(TCP 报文段中数据部分的最大长度) 的协商,以便在传输过程中进行分片

在网络传输的过程中,如果中间设备(例如路由器)的 MTU 比较小,就会 MSS clamping

MSS clamping 是一种 TCP 优化技术,用于解决 TCP 数据包在传输过程中可能发生的分片问题

它会检查 TCP SYN 包中的 MSS 选项,并将其值与网络链路的 MTU 进行比较

如果 MSS 值大于 MTU,就将 MSS 值设置为 MTU 减去 IP 头部和 TCP 头部的长度,从而保证 TCP 数据包的大小不会超过网络链路的 MTU,避免发生 IP 分片

在 TCP 连接建立后,双方会根据 MSS 值来控制每个 TCP 数据包的大小,从而保证 TCP 数据包不会超过网络链路的 MTU,提高网络传输的效率

但是对于面向无连接的协议(例如 UDP ),这时候该怎么办呢?

我们知道以太网规定 MTU 范围上限为 1500 字节,那么理论上 UDP 能传输的数据包大小上限为:

MTU(1500) - IP Header(20) - UDP Header(8) = 1472 字节

  • 如果 UDP 数据包小于等于1472 个字节,那么正常发送不用分片
  • 如果 UDP 数据包超过 1472 个字节,那么移交网络层进行分片并在接收方进行重组

但我们需要知道的是,UDP 包进行分片的时候不像 TCP 那样每个分片里面都复制一个 Header

而是第一个分片有 UDP Header,其余的都没有

所以接收方拿到 UDP 分片包之后在传输层就得先进行重组成一个完整的 UDP 包然后才能交给上一层

这样就会导致一个问题:如果在传输过程中其中一个 UDP 分片包丢了,造成 UDP 包重组失败,接收方会把整个包给丢掉

但是又因为 UDP 没有重传机制,就会导致 UDP 发送方不知道接收方丢了这个包

然后发送方就会一直发包,接收方一直丢包

所以说最好不要发超过接收方 MTU 大小的 UDP 数据包

但面向无连接的 UDP 是怎么知道对方 MTU 的呢?(TCP 有 MSS 协商)

为此我在虚拟机上简单做了一个实验

  • 环境

    • CentOS 7
  • 服务器 A
    • IP:192.168.149.130
    • MTU:800
  • 服务器 B
    • IP:192.168.149.131
    • MTU:1500

然后用 B 服务器去 ping 服务器 A,发送一个大小为 1500 bytes 的数据

# -M do 表示不分片
# -p 选项用于指定数据包的内容
# -c 2 指定发送数据包的数量为2
# -s 指定数据包的大小
ping -c 2 -s 1000 -M do -p $(echo -n abcdefghijklmnopqrstuvwxyz | xxd -p) 192.168.149.130

结果发现服务器 A 全部接受了,按理说 A 的 MTU 是 800,又因为设置了不分片,应该丢弃这个包才对

然后我们用 B 服务器去 ping 服务器 A,发送一个大小为 1600 bytes 的数据

发现超出服务器 B 的 MTU (1500)了,又因为不允许分片,导致包不能发出

ping -c 2 -s 1600 -M do -p $(echo -n abcdefghijklmnopqrstuvwxyz | xxd -p)   192.168.149.130

跟我想象的不太一样,服务器 A 收到服务器 B 发送的超过自身 MTU 大小的包应该是丢弃,然后回复一个:

Type=3 (Destination Unreachable) and code=4, packet too big and DF is set

表示发送方数据包无法到达目的地且无法分片

后面我查了一下,应该是本地环境即两个虚拟机之间的网络比较简单,导致网卡能接受这种不合理的包,如果有懂的小伙伴可以私信我

但是这个实验至少证明了一点:即服务器不会去关心对方的 MTU,只会根据自己的 MTU 去进行分片

然后我又查阅了大量的资料,我看到一个比较贴切的答案就是:

我们来看下上面这段内容,可以得出

在 RFC 中,Internet (IPv4) 标准规定 MTU 最小是 576 bytes

所以对于 UDP 来讲,能发的有效数据(Payload)只要不超过 508 bytes

576 bytes (MTU) - 60 bytes (IP header 20 bytes + IP option 0-40 bytes) - 8 bytes (UDP Header)= 508 bytes

我管你服务器的 MTU 是多少,我只发送全世界最小的二层包,总没问题了吧?

很多情况下 IP header 是达不到 60 bytes的,所以一般 UDP 的 Payload 也会是是 512 bytes

总结一下:

  • 不同于 TCP ,UDP 这个简单的协议并不关心对方的 MTU 这些问题;如果你要基于 UDP 实现一个协议,就要自己处理超过 MTU 的问题
  • 为了避免分片问题,UDP 只发不超过 IPV4 MTU 范围下限(576 bytes)的包(即UDP 数据包的最大 Payload 是 512 字节
  • 上述讨论针对的是 IPV4,而非 IPV6

Beej's Guide to Network Concepts

domain name system - Why DNS through UDP has a 512 bytes limit? - Server Fault

MTU 和 UDP (以及基于 UDP 的协议) | 卡瓦邦噶! (kawabangga.com)

计算机网络那些事之 MTU 篇 pt.2的更多相关文章

  1. mysql那些事之索引篇

    mysql那些事之索引篇 上一篇博客已经简单从广的方面介绍了一下mysql整体架构以及物理结构的内容. 本篇博客的内容是mysql的索引,索引无论是在面试还是我们日常工作中都是非常的重要一环. 索引是 ...

  2. 你所不知道的html5与html中的那些事第三篇

    文章简介: 关于html5相信大家早已经耳熟能详,但是他真正的意义在具体的开发中会有什么作用呢?相对于html,他又有怎样的新的定义与新理念在里面呢?为什么一些专家认为html5完全完成后,所有的工作 ...

  3. Verilog HDL那些事_建模篇笔记(实验七:数码管电路驱动)

    1.同步动态扫描 多个数码管的显示采用的是同步动态扫描方法,同步动态扫描指的是:行信号和列信号同步扫描,是一种并行操作. 2.数码管驱动电路实现思路      如果要求数码管显示我们想要的数字,首先需 ...

  4. 移动前端工作的那些事---前端制作篇之meta标签篇

    移动端前端制作有些地方不同于互联网,这篇主要讨论的是meta标签.meta标签位于head标签之间.是主要辅助HTML结构层的.meta标签不管在互联网前端还是在移动端都起了很重要的作用.这里只讨论移 ...

  5. Verilog HDL那些事_建模篇笔记(实验九:VGA驱动)

    1.了解VGA协议 VGA协议有5个输入信号,列同步信号(HSYNC Signal),行同步信号(VSYNC Signal),红-绿-蓝,颜色信号(RGB Signal). 一帧屏幕的显示是由行从上至 ...

  6. Verilog HDL那些事_建模篇笔记(实验八:键盘解码)

    1.PS2接口与协议时序图 对于PS2的接口来说,需要额外关注的是PIN5与PIN1,一个是时钟,一个是数据.PS2协议对数据的移位是“CLOCK下降沿”有效,其CLOCK的频率通常在10KHz左右. ...

  7. Verilog HDL那些事_建模篇笔记(实验三:按键消抖)

    实验三:按键消抖 首先将按键消抖功能分成了两个模块,电平检查模块和10ms延迟模块.电平检测模块用来检测按键信号的变化(是否被按下),10ms延迟模块用来稳定电平检查模块的输入,进而稳定按键信号,防止 ...

  8. 关于TP3.2微信开发那点事(基础篇)

    许久没有为博客更新内容,今天我将过去一周做的微信服务号的相关心得体会在此分享,具体如何申请成为服务号的相关流程文档都有,可根据要求完成: 开发第一步:开发前配置: AppID-->微信号的&qu ...

  9. Verilog HDL那些事_建模篇笔记(实验一,实验二)

    实验一:永远的流水灯 扫描频率配置为100Hz,即是说扫描周期为10ms.这里需要注意的是扫描周期的概念.流水灯嘛,顾名思义,扫描周期指的是流水灯扫一轮所需要的时间.听到说周期,就应该想到在建模的时候 ...

  10. 聊聊HTTP请求那一些事_HttpWebRequest_一篇就够了

    ​最近工作比较忙,很久没有写东西了,今天抽点时间整体一下最近工作的一个知识点小结.http请求对我们来说一点都不模式,程序员的我们有可能天天就是和这一些打交道.无论是BS架构的程序,前后端的数据交互, ...

随机推荐

  1. PySimpleGU之运行多个窗口

    这是PySimpleGUI继续简单的地方,但是问题空间刚刚进入了"复杂"领域. 如果您希望在事件循环中运行多个窗口,则有两种方法可以执行此操作. 当第二个窗口可见时,第一个窗口不会 ...

  2. 四月二十八号Java基础知识

    1.由于Thread类位于java.lang包中,因而程序的开头不用import导入任何包就可直接使用try{ sleep((int)(1000*Math.random()));//sleep()方法 ...

  3. 【享元设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

    简介 享元模式(Flyweight Pattern),是一种结构型设计模式.主要用于减少创建对象的数量,以减少内存占用和提高性能.它摒弃了在每个对象中保存所有数据的方式,通过共享多个对象所共有的相同状 ...

  4. Rust中的into函数和from函数

    1.Rust中的into函数和from函数是做什么用的? into函数是Rust语言中的一个转换函数,它属于Into trait.它可以将一个类型转换为另一个类型.实现了From trait的类型会自 ...

  5. 谈谈selenium中的clear后输入内容异常的处理

    谈谈selenium中的clear后输入内容异常的处理 案例 在线考试项目的登录:http://124.223.31.21:9097/#/ 代码 from selenium import webdri ...

  6. 龙芯(Loongarch64),在Linux虚拟一个龙芯OS体验下

    前言 想体验下龙芯OS,但是又没有龙芯开发板或者龙芯实体机.手头上只有一个X64环境的Linux发行版,应该怎么做呢? 概括 其实非常简单,可以通过Chroot命令和Qemu在X64的指令集系统上模拟 ...

  7. cocos2d-x场景间参数传递

    1>使用全局变量     这个就不详细说明了.   2>切换时传递     2.1>在secondScene.h 中加入成员变量,如 int sceneNum;         并在 ...

  8. day04-商家查询缓存03

    功能02-商铺查询缓存03 3.功能02-商铺查询缓存 3.6封装redis工具类 3.6.1需求说明 基于StringRedisTemplate封装一个工具列,满足下列需求: 方法1:将任意Java ...

  9. 如果你项目使用了MyBatis-Plus你一定要用它

    还是先举个例子,魂斗罗小游戏应该很多90后都玩过,那个时代没有Iphone,没有各种电子产品(小学初中时代),这种小游戏应该就是很多90后的青春,反正那个时候只要放假就白天黑夜得玩.它就是那种2个好基 ...

  10. CSS6大种选择器

    一.常用的css基本选择器(4种) 1.标签选择器 结构: 标签名{css属性名:属性值}作用:通过标签名,找到页面中所有的这类标签,设置样式 注意:1.标签选择器选择的是一类标签,而不是单独的一个2 ...