【问题标题】:How does the UDP checksum change for IP fragments?IP 片段的 UDP 校验和如何变化?
【发布时间】:2015-01-22 13:20:49
【问题描述】:

我需要用 c 编写一个基本的网络堆栈,但对正确的做法有一些疑问。假设我只需要支持 L4 的 UDP 和 L3 的 IP。

当我想发送需要碎片化的大消息时。处理此问题的正确顺序是什么?

1) 初始化 udp 头并计算整个数据字段的校验和(加上 udp 和伪头)然后对数据字段进行分段,为每个分段构建 IP 头,然后发送分段。

2) 对数据字段进行分段,然后构建一个 udp 标头,并在每个分段的前面添加不同的校验和。然后为每个片段构建一个 IP 标头以附加该标头。然后发送我们的片段。

我的困惑源于 udp 校验和是否应该包含整个组装的数据报,还是只包含单个片段。非常感谢您提供的任何帮助。

【问题讨论】:

  • 你有没有想过在你的c程序中使用netstat?您可以从中获取所有信息。
  • 它没有改变。校验和是在整个数据报上计算的。碎片化发生在较低的级别。

标签: c sockets networking udp


【解决方案1】:

网络层彼此独立工作。当 IP 层对数据包进行分段时,UDP 层对此一无所知。当应用层 UDP 侦听器接收到数据包时,它已经被重新组装,并且不知道数据包曾经被分段。

有了这些知识,我们可以说 UDP 校验和必须覆盖完全组装的数据包,并且在分片期间不必更改。实际上,UDP 标头中的什么都没有发生变化。

要对分段数据包进行错误检查,请使用 IPv4 校验和标头字段。 IPv6 标头没有校验和字段,因为预计较低层的数据包传递无误。

当您对 IPv4 数据包进行分段时,您必须重新计算分段的 IPv4 标头。 IPv4 wikipedia entry 告诉我们在对数据包进行分段时必须更改的内容:

  • 总长度字段是段大小。
  • 为除最后一个段之外的所有段设置了更多片段 (MF) 标志,该标志设置为 0。
  • 分段偏移字段是根据原始数据有效负载中分段的偏移量设置的。这以 8 字节块为单位。
  • 重新计算 [IPv4] 标头校验和字段。

因此,总而言之,您执行以下操作:

  1. 获取应用程序级数据并将其包装在 UDP 标头中。
  2. 将带有 UDP 标头的数据包交给 IP 层。
  3. 将数据分成片段。
  4. 对于每个分片,在其上放置一个 IPv4 分片标头。
    • 将片段交给第 2 层,并将第 2 层标头放在上面。
    • 发送片段。

【讨论】:

  • 感谢您的详细回复。是否有避免过多 memcpys 的典型方法?例如,在我通过启动数据并创建 udp 标头之后,通常是否将它们一起复制到新的地址空间中?或者改为单独维护它们。如果单独维护,那么数据字段可以被分段,然后 udp 标头和数据片段都可以在发送之前被 memcpy 到最终的以太网有效负载。感谢您的帮助 - 我的代码运行良好,我只想以正确的方式进行。
  • 数据包副本是吞吐量杀手。尽你所能避免它们。如果你真的有很多时间来实现这个,你希望将你的内存预先分配到一个池中。没有malloc/free。然后,当您第一次(也是唯一一次)将用户数据复制到您自己的内部缓冲区时,将其复制到缓冲区的一半。因此,当您向下通过网络堆栈时,您在缓冲区的前面有足够的空间来添加标头,而无需从上层移动任何数据。通过指向缓冲区的指针跟踪标头位置。
【解决方案2】:

数字 1 和数据包之前的整体校验和应与重构回原始形式的校验和相匹配

【讨论】:

  • 那么关于 udp 标头长度和校验和字段的规则是什么?应该只在第一个片段中设置它们吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-01
  • 2014-06-15
  • 2014-08-16
  • 2010-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多