为啥ip片段必须是8字节的倍数

Posted

技术标签:

【中文标题】为啥ip片段必须是8字节的倍数【英文标题】:Why the ip fragments must be in multiples of 8 bytes为什么ip片段必须是8字节的倍数 【发布时间】:2011-12-12 09:14:22 【问题描述】:

在教科书计算机网络 James F.Kurose Fifth Ed, ch4 中提到

ip 片段必须是 8 字节的倍数,因为 IP 标头 中的 Flags 占用 3 位。我不明白为什么ip碎片必须是8字节的倍数。

【问题讨论】:

【参考方案1】:

除最后一个片段外,每个片段都必须包含 8 字节数据的倍数。

Fragment Offset 可以容纳 8192 (2^13) 个单位,但数据报不能有 8192 * 8 = 65536 字节的数据,因为 IP 标头的“总长度”字段记录了包括标头和数据在内的总大小。

IP 标头至少有 20 个字节长,因此“Fragment Offset”的最大值被限制为 8189,这为最后一个片段留出了 3 个字节的空间。

希望这会有所帮助。

【讨论】:

感谢@Wayne Shears 的回答,正如您所说:Fragment Offset 可以容纳 8192 (2^13) 个单位 [什么是平均单位?你的意思是字节吗?] 但是数据报不能有 8192 * 8 = 65536 字节的数据 [为什么?] 因为 IP 标头的“总长度”字段记录了包括标头和数据在内的总大小 [我所知道的是总长度 = 报头大小 + 有效负载。总长度为 16 ,因此值将上升到 2^16 即 65536 ,我认为有什么问题吗?].【参考方案2】:

请注意,Fragment Offset 字段以 8 字节为单位表示,而不是以字节为单位。 这就是为什么每个片段内的有效负载大小(除了最后一个片段)必须是 8 字节的倍数。

由于 Fragment Offset 编码为 13 位,因此它的范围在 0 到 8191 个 8 字节单位之间。但是,由于 Total Length 也考虑了 IP Header,Fragment Offset 最大限制实际上是 8189 个单位,而不是 8191 个单位,见下文:

总长度编码为 16 位,这意味着它被限制为 65535 个字节。 然后,由于 IP 标头至少为 20 字节,因此有效负载被限制为最大 65535 字节 - 20 字节 = 65515 字节。 将这 65515 个字节划分为 8 个字节单元,结果可能是最大 8189 个单元,因此分片偏移量被限制为最大 8189 个单元。

将片段偏移值设置为此最大值 8189 的 IP 片段可以具有最大 3 个字节的有效负载:

最大 65535 字节 - 最小 20 字节 -(8189 个单位 * 每个单位 8 个字节)= 最大 3 个字节

鲁尔

【讨论】:

【参考方案3】:

我没有从这里的其他答案中获得太多好处。他们似乎只是顺便刷了一下真正的问题,同时试图解释他们看到的另一个问题,所以这里是真正的答案:

消息长度字段的位数与分片字段的位数不同。

[        Length        ] <-- 16 bits
[ Flag ][   Fragment   ] <-- 3 bits + 13 bits

消息长度字段测量整个消息,跨越该消息的所有片段

当发送一个大数据包时,它会被分成多个片段,因此您需要标记该片段并跟踪该片段中的消息部分,并在所有片段到达时将其重新排序。你得到 13 位来描述片段的序列。 长度是一个16位整数,所以它的容量(16位)是2^16 - 1 = 65536-1 = 65535。这为您提供了 65535 个不同的字节,因此 IP 消息的长度最多为 65535 个字节。

片段偏移量是字节的度量,但不能适应消息中的字节数

理想情况下,我们希望以与长度相同的单位来衡量片段,即字节

但我们只有 13 位的 Fragment!

他们希望以字节为单位保持 Fragment 偏移量的度量,因此他们不得不想办法将 16 位放入 13 位中。他们发明了一种奇怪的位映射来为他们做到这一点:

奇怪的位映射

他们意识到,数字每减少 1 位来表示其最大数(例如,通过去掉一位,从 16 位减少到 15 位),您可以拥有的唯一索引的数量是除以 2。15 位只能表示 2^15 - 1 = 32768-1 = 32767 唯一位置。 14 位 --> 再次除以 2; 13 位 --> 再次除以 2。为了能够跟踪相同的总字节数,它必须跳过一些字节并仅索引每个2^n 字节,其中 n 是从 Fragment 偏移值中取出的位数。由于 Fragment 偏移量需要使用 13,它带走了 3 位,所以它只能索引每 8 个 (2^3) 字节,因此索引是针对 8 字节块的。因此8 * Fragment Offset 来计算每个片段的实际字节偏移量。

注意事项

片段值是从第一个片段的第一个字节开始的偏移量。出于某种奇怪的原因,他们决定以字节为单位测量偏移量,而不是片段的数量——即使字节需要比索引更多的数据。将片段偏移量简单地设为索引值(片段编号)可能更明智——但他们没有这样做!

【讨论】:

【参考方案4】:

Wayne 所说的以及实际上在终端主机中使用偏移量的事实,以便它们可以有效地将片段高效地存储在内存中,即连续存储。偏移量显示片段相对于整个数据报的相对位置。这就是为什么偏移量必须是 IP 片段必须是 8 字节的倍数,因为您实际上要做的是右移 3 位(因此是 13 位)。

【讨论】:

【参考方案5】:

这里 (https://cs.nyu.edu/courses/fall98/G22.2262-001/class11.txt) 给出:片段偏移量以 8 字节(64 位)为单位。这是因为片段偏移字段比总长度字段短 3 位,即 16 位(而 2^3 为 8)。

【讨论】:

以上是关于为啥ip片段必须是8字节的倍数的主要内容,如果未能解决你的问题,请参考以下文章

IP协议

位图存储图像数据每行字节数为4的倍数

TCP/IP协议 怎么用JAVA发送和接收二进制数据 要具体实例

字节对齐

为啥在只需要一个字节时,Rust 使用两个字节来表示这个枚举?

程序员应该懂的ip地址知识汇总