我已经阅读了许多关于 UDP 数据包大小的文章,但无法得出正确的结论。
许多服务将最大的 UDP 数据包限制为 512 字节(如 dns)
给定 Internet 上的最小MTU为 576 ,IPv4 标头的大小为 20 字节,UDP 标头的大小为 8 字节。这留下了 548 个字节可用于用户数据
我是否能够使用最大 548 大小的数据包而不会产生数据包碎片?或者 DNS 的创建者是否知道某些东西,以及为什么他们将其限制为 512 字节。
我什至可以安全地超过 548 字节吗?
我已经阅读了许多关于 UDP 数据包大小的文章,但无法得出正确的结论。
许多服务将最大的 UDP 数据包限制为 512 字节(如 dns)
给定 Internet 上的最小MTU为 576 ,IPv4 标头的大小为 20 字节,UDP 标头的大小为 8 字节。这留下了 548 个字节可用于用户数据
我是否能够使用最大 548 大小的数据包而不会产生数据包碎片?或者 DNS 的创建者是否知道某些东西,以及为什么他们将其限制为 512 字节。
我什至可以安全地超过 548 字节吗?
最大安全 UDP 有效负载为 508 字节。这是一个 576 的数据包大小(“最小最大重组缓冲区大小”),减去最大 60 字节 IP 标头和 8 字节 UDP 标头。
任何这种大小或更小的 UDP 有效负载都保证可以通过 IP 传送(尽管不保证传送)。任何更大的东西都可以被任何路由器以任何理由直接丢弃。除了仅 IPv6 路由,最大有效负载为 1,212 字节。正如其他人所提到的,在某些情况下可以添加额外的协议头。取而代之的是更保守的 300-400 字节左右的值。
最大可能的 UDP 有效负载为 67 KB,分成 45 个 IP 数据包,增加了 900 字节的额外开销(IPv4,MTU 1500,最少 20 字节的 IP 标头)。
任何 UDP 数据包都可能被分段。但这并不太重要,因为丢失一个片段与丢失一个未分片的数据包具有相同的效果:整个数据包都被丢弃了。使用 UDP,无论哪种方式都会发生这种情况。
IP 数据包包括一个片段偏移字段,它指示 UDP 片段相对于其 UDP 数据包的字节偏移量。该字段为 13 位,允许 8,192 个值,以 8 字节为单位。因此,IP 数据包可以引用的此类偏移的范围是 0...65,528 字节。作为一个偏移量,我们为最后一个 UDP 片段添加 1,480 以获得 67,008。减去第一个片段中的 UDP 标头,我们得到了一个不错的 67 KB。
来源:RFC 791、RFC 1122、RFC 2460
UDP 数据包最大大小的理论限制(在 Windows 上)为 65507 字节。这记录在这里:
正确的最大 UDP 消息大小为 65507,由以下公式确定:0xffff - (sizeof(IP Header) + sizeof(UDP Header)) = 65535-(20+8) = 65507
话虽如此,大多数协议的大小都限制在小得多——通常是 512 或偶尔是 8192。如果你在可靠的网络上,你通常可以安全地高于 548——但如果你在整个互联网上广播,则更大的你去,你越有可能遇到数据包传输问题和丢失。
576 是最小最大重组缓冲区大小,即每个实现必须能够重组至少该大小的数据包。有关详细信息,请参阅IETF RFC 1122。
本文介绍了最大传输单元 (MTU) http://en.wikipedia.org/wiki/Maximum_transmission_unit。它规定 IP 主机必须能够处理 576 字节的 IP 数据包。但是,它指出最小值是 68。 RFC 791:“每个 Internet 模块必须能够转发 68 个八位字节的数据报,而无需进一步分段。这是因为 Internet 标头可能最多 60 个八位字节,而最小分段为 8 个八位字节。”
因此,508 = 576 - 60 (IP header) - 8 (udp header) 的安全数据包大小是合理的。
如 user607811 所述,必须重新组装其他网络层的碎片。 https://www.rfc-editor.org/rfc/rfc1122#page-56 3.3.2 重组 IP 层必须实现 IP 数据报的重组。我们指定可以由 EMTU_R 重组的最大数据报大小(“Effective MTU to receive”);这有时称为“重组缓冲区大小”。EMTU_R 必须大于或等于 576
IPv4最小重组缓冲区大小为 576,IPv6 为 1500。从此处减去标头大小。请参阅W. Richard Stevens 的 UNIX 网络编程:)
我在这里阅读了一些很好的答案;但是,有一些小错误。有些人回答说 UDP 标头中的消息长度字段最大为 65535 (0xFFFF);这在技术上是正确的。有些人回答说实际最大值是(65535 - IPHL - UDPHL = 65507)。错误在于 UDP 标头中的消息长度字段包括所有有效负载(第 5-7 层),加上 UDP 标头的长度(8 字节)。这意味着如果消息长度字段是 200 字节 (0x00C8),则有效负载实际上是 192 字节 (0x00C0)。
硬而快的是,IP 数据报的最大大小是 65535 字节。这个数字是 L3 和 L4 标头的总和,加上第 5-7 层有效负载。IP 标头 + UDP 标头 + 第 5-7 层 = 65535(最大值)。
对于 UDP 数据包的最大大小,最正确的答案是 65515 字节 (0xFFEB),因为 UDP 数据报包含 UDP 标头。对于 UDP 有效负载的最大大小,最正确的答案是 65507 字节,因为 UDP 有效负载不包括 UDP 标头。
512是你最好的选择。它在其他地方使用,是一个很好的偶数(1024 的一半)。
鉴于 IPV6 的大小为 1500,我会断言运营商不会为 IPV4 和 IPV6 提供单独的路径(它们都是不同类型的 IP),迫使他们使用旧的、冗余的、维护成本更高的 ipv4 设备并且不太可靠。这没有任何意义。此外,这样做可能很容易被认为是为某些流量提供优惠待遇——根据他们可能不太在意的规则,这是不可以的(除非他们被抓住)。
所以 1472 对于外部使用应该是安全的(尽管这并不意味着像 DNS 这样不了解 EDNS 的应用程序会接受它),如果您正在谈论内部网络,您更有可能知道您的网络布局在这种情况下巨型数据包大小适用于非分段数据包,因此对于 4096 - 4068 字节,对于具有 9014 字节缓冲区的英特尔卡,包大小为......等等......8086 字节,最大......巧合吗? 暗笑
****更新****
各种答案给出了 1 个软件供应商允许的最大值或假设封装的各种答案。用户没有要求可能的最低值(如安全 UDP 大小的“0”),而是最大的安全数据包大小。
可以多次包含不同层的封装值。因为一旦你封装了一个流——没有什么可以禁止,比如说,在它下面有一个 VPN 层,在它上面有一个完全重复的封装层。
由于问题是关于最大安全值,我假设他们正在谈论可以接收的 UDP 数据包的最大安全值。由于不保证 UDP 数据包,如果您收到 UDP 数据包,最大安全大小将是 IPv4 上的 1 个数据包或 1472 字节。
注意——如果您使用 IPv6,最大大小为 1452 字节,因为 IPv6 的标头大小为 40 字节,而 IPv4 的大小为 20 字节(无论哪种方式,UDP 标头仍必须允许 8 个字节)。
UDP 不是“安全的”,所以问题不是很好 - 但是 -
如果您发送 9217 或更多 (mac) 或 65508+ (linux/windows),则套接字发送函数会返回错误。
上面讨论碎片和 MTU 等的答案是题外话 - 所有这些都发生在较低级别,对您来说是“不可见的”,并且不会在很大程度上影响典型连接的“安全”。
但是,要回答实际问题的含义-不要使用UDP-使用原始套接字,以便更好地控制一切;由于您正在编写游戏,因此您需要深入研究标志以优先考虑您的流量,因此您不妨同时摆脱 UDP 问题。
没有一个。
我将完全搁置任何“UDP 是尽力而为”的推理,而只关注“最大安全 UDP 数据包大小”,这意味着“足够小以绝对避免沿路径某处出现任何碎片”。
重要背景:
唯一可以在不分片的情况下传输的数据包大小是 IPv4 的 24 字节和 IPv6 的 56 字节,因为片段的最小 IP 标头是 20/48 字节 (v4/v6) 并且片段必须至少有 4/8字节 (v4/v6) 有效载荷数据。因此,IP 层以下的传输系统至少不能传输这些大小的数据包,因此 [根本] 不能用于传输 IP 流量。-回答“UDP 中的 MTU 65507 怎么样......?” .
根据上面的答案,这是因为在那个长度下,IP 分片机制无法运行——它无论如何只能生成一个分片。
... IP 标准要求每台 IP 主机都能够接收总大小为 576 字节的 IP 数据包...。但是请注意,标准并没有说 576 没有分片,所以即使是 576 字节的 IP 数据包也可能会找到本身在两个主机之间[沿着源和目标之间的路径的某个地方] 碎片化。
因此,即使您选择了最小的 UDP 有效负载,即使您选择了最小的 UDP 有效负载,任何比互联网协议可能做的更大的东西,实际上都可能会因为被“不可见”临时封装到略高于限制的路径而发现自己碎片化: 576 - 8(用于 UDP 标头)- 20 (IPv4) 或 40 (IPv6) = 528 的最小值(以防您不确定将使用 v4 还是 v6)。
您可能试图避免碎片化的一个原因是,它确实增加了数据包整体丢失的可能性。仅仅由于更高的开销,更多的数据包将意味着更大的失败可能性,更不用说每个数据包(甚至是一个片段)都代表另一个丢失的“机会”。当然,如果它碰巧被传递到某个链接,它会因为太大而丢弃它......
操作系统级别的 TCP 实现会尝试在 TCP 层中选择最高安全的 MTU,包括处理它有时会动态变化,因为源和目标之间的部分路径可能会因数据包而异。
对于 UDP,这整个问题也变成了你的问题:而且它并不像“使用肯定不会分片的最大的”那么简单。
RFC2460 第 5 节有这个说法(关于 IPv6 的最小 MTU)。
IPv6 要求 Internet 中的每个链接的 MTU 为 1280 字节或更高。在任何无法一次性传送 1280 字节数据包的链路上,必须在低于 IPv6 的层提供特定于链路的分段和重组。
因此,碎片也可能发生在IP级别以下,其中沿路径的两个主机之间的特定链接决定对其进行碎片化,然后可能将碎片推向平行管道……让它们在另一端重新组装成一个数据包。一个链接。
如果这些片段出现乱序,则重新排序机制可能会错误地重新组装数据包,甚至没有意识到它重新排序了其中的一部分。
当然,如果硬件遵循 IP 规范,它应该能够通过检查 IP 标头的片段偏移部分来注意到数据包出现了乱序,但大多数链路协议只是按照接收到的顺序重新组装片段,不用担心乱序的数据包接收。
现在,如果该“较低级别”互连本身用作网络……例如在大型交换机的核心中,那么在重负载和许多并行路径下,这些片段可能会脱离重新组装前订购。
这是超级邪恶的,但有时可能确实会发生,导致偶尔仍然交付但严重损坏的数据包,它仍然通过简单的基于异或的校验和测试......这恰好是 IP 校验和。
TCP 只是设置“不分段”并处理它,但 UDP 会清除这一点......所以如果您使用的是 UDP,您还应该假设您的字节流有时可能会在数据包内重新排序...... . 因此,您应该使用可以捕获重新排序的校验和方法来验证您的数据。
大多数链路无论如何都会做 1500 MTU,但链路层有不同的最小和最大数据报大小:
不幸的是,UDP 标头本身是 8 个字节......所以这意味着,唯一可以避免碎片的 UDP 有效负载......是零!(并且无论如何都只适合最小的 IPv6 数据包)。
最好/合理的课程可能是为您的 UDP 数据报使用 512,并自己检查数据报中出现乱序的数据,以及处理乱序到达的数据包。(IE,完全不要依赖 IP 为您丢弃损坏的数据包)。
我担心我会引起不安的反应,但是,如果我错了,或者那些看到这个问题并对答案感兴趣的人,请向我澄清:
我对https://www.rfc-editor.org/rfc/rfc1122的理解,它的状态是“官方规范”,因此是此问题中使用的术语的参考,既没有被另一个 RFC 取代,也没有勘误表与以下内容相矛盾:
理论上,即。根据书面规范,https: //www.rfc-editor.org/rfc/rfc1122#section-4 给出的 UDP没有“数据包大小”。因此答案可能是“不确定的”
在实践中,这可能是这个问题所寻求的(并且可以针对当前正在使用的技术进行更新),这可能会有所不同,我不知道。
如果我造成了不安,我深表歉意。https://www.rfc-editor.org/rfc/rfc1122#page-8根据我所听到的,“互联网协议套件”和“架构假设”并没有让我明白我的“假设” ,即层是分开的。IE。UDP所在的层不必关心IP所在的层(IP层确实有重组、EMTU_R、碎片和MMS_R之类的东西(https://www.rfc-editor.org/rfc/rfc1122#第 56 页))
UDP 单独使用时是不可靠的协议。但实际上并不是那么不可靠。当然,如果你将它用于银行软件,它是不可靠的,但如果你将它用于在线游戏或视频/音频流,它是非常可靠的。
如果您对原始数据感兴趣,请访问https://www.openmymind.net/How-Unreliable-Is-UDP/并查看 Karl Seguin 收集的统计数据。
TLDR:UDP 的平均可靠性为 98.64%,而 TCP 为 100%。
如果担心丢包的可能性为 1.36%,则使用 TCP,否则使用 UDP。