什么是 MTU
最大传输单元是绝对不会在其传输的整个路径中分段的数据包的最大大小。请注意,正如 flakes 所提到的,这种碎片通常会透明地发生,即使是在 UDP 上!因此,即使您大大超过了路径 MTU,您的数据包也可能会安全地重新组装到达。
因此,MTU 主要是一种工具,可以降低中间节点的传输开销,并可能降低由于将数据包保留在最慢的部分进行重组而产生的延迟。
一般如何查找 MTU
RFC 4821是这个过程的一个很好的概要。
简而言之:发送带有“do-not-fragment”标志和一些垃圾填充数据的 ICMP ping。侦听 ICMP“数据包太大”消息。如果您收到 ping 回复,请使用更大的 ping 数据包重新发送。如果您收到“数据包太大”,请使用较小的 ping 重新发送。通过这种方式,您可以对您的实际 MTU 进行二进制搜索。
不幸的是,因为这是多播...
RFC 4821 的第 5.4 节说,
在多播目标地址的情况下,数据包的副本可能会经过许多不同的路径到达许多不同的节点。到多播目的地的“路径”的本地表示实际上必须代表一组潜在的大路径。
最低限度,一个实现可以维护一个单一的 MTU 值,用于来自该节点的所有多播数据包。这个 MTU 应该足够小,以至于预计它小于组成多播树的所有路径的路径 MTU。如果通过单播方式获知的路径 MTU 小于配置的多播 MTU,则多播 MTU 可以减少到该值。这种方法可能会导致使用比许多路径所需的更小的数据包。
如果使用多播的应用程序获得完整的传递报告(不太可能,因为此要求具有较差的扩展特性),PLPMTUD 可以在多播协议中实现,以便跨组学习的最小路径 MTU 成为该组的有效 MTU。
因此,为多播用户找到 MTU 可能不太可行。
不幸的是,因为这是Java...
Java 不支持 ICMP。完全没有。而且通过 UDP 实现这一点实际上是不可能的——由于透明的重组,我们永远不知道碎片何时发生。
所以我们有两个选择
- 不要太担心数据包碎片,但要为接收者的缓冲区大小声明一个合同。例如,对于 RUDP,每一方都在连接开始时声明其接收缓冲区大小,并且发送方在任何发送的数据包中都不得超过该大小。
- 对 MTU 做出最悲观、最糟糕的估计。所有 IPv4 硬件必须传输 68 字节的数据包而不分片(根据 RFC 791),或 576 字节的重组(根据 RFC 1122)。所有 IPv6 硬件必须传输 1280 字节的数据包而不进行分段(根据 RFC 2460),并且只有源节点可以对 IPv6 中的数据包进行分段(!),所以如果您自己的主机没有分段它,那很好。
TL,博士;对于 IPv4 / IPv6,我可能会分别使用 576 / 1280。
(注意:IPv4 UDP 数据包减去 68 个字节,IPv6 UDP 数据包减去 48 个字节)