c - UDP校验和计算

标签 c network-programming udp checksum

/usr/include/netinet/udp.h 中定义的 UDP header 结构如下

struct udphdr
{
  u_int16_t source;
  u_int16_t dest;
  u_int16_t len;
  u_int16_t check;
};

header 的检查字段中存储什么值?如何验证校验和是否正确?我的意思是校验和是根据什么数据计算的? (只是 udp header 还是 udp header 加上其后面的有效负载?)

谢谢。

最佳答案

UDP 校验和对整个有效负载、 header 中的其他字段、IP header 中的某些字段进行。。伪 header 是根据 IP header 构造的,以便执行计算(通过该伪 header 、UDP header 和有效负载完成计算)。包含伪 header 的原因是捕获已路由到错误 IP 地址的数据包。

基本上,在接收端, header 和数据区域的所有 16 位字都会相加(以 16 位换行),并根据 0xffff 检查结果。

在发送端,情况稍微复杂一些。对所有 16 位值执行补码和,然后从该值中取出补码(即反转所有位)以填充校验和字段(附加条件是计算出的校验和为零将更改为所有校验和)一位)。

一个的补码和只是所有一个的补码值的和。有点复杂。

基本上,您有一个从零开始运行的 16 位累加器,然后将每个 16 位值添加到其中。每当这些加法之一产生进位时,该值就会被环绕,并再次向该值加一。这有效地获取 16 位加法的进位位并将其添加到值中。

<小时/>

As an aside, and this is pure conjecture on my part but this could probably be efficiently done by use of the ADC (add with carry) instruction rather than ADD (surprisingly enough, add), or whatever equivalent instructions were available on your CPU at the time.

If there were no carry, ADC would just add the zero bit from the carry. In the days when this stuff was done (and yes, unfortunately, I am that old), memory was far more of a constraint than speed, not so much the case nowadays, so saving a few bytes in your code could well elevate you to the level of demi-god-emperor-of-the-universe :-)

<小时/>

请注意,自从两次最大的进位以来,您永远不必担心第二次进位(或者如果您使用上一段中提到的方法,则与下一个 ADC 进行两次进位) 16 位值相加后会产生(从 0x1fffe 截断)0xfffe - 加一将永远不会导致另一次进位。

一旦计算出补码和,将其位反转并插入到数据包中,这将导致接收端的计算产生0xffff,当然假设传输没有错误.

值得注意的是,有效负载始终会被填充,以确保存在整数个 16 位字。如果被填充,长度字段会告诉您实际长度。

RFC768是详细说明这一点的规范。

关于c - UDP校验和计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1480580/

相关文章:

http - 通过 TCP/IP 端口不断读取/写入数据。哪一个?

tcp - 为什么 UDP 在有损网络中表现优于 TCP

java - DatagramChannel 数据包监听器占用高 CPU 资源

java - 更新 UI 时接收多个 UDP 数据包

c - 找到最小元素,然后返回该最小元素所在列的索引

c - 让我的程序运行时出现问题

python - 使用 C API 创建在 python 中声明的 python 类的实例

c - 同时从多个线程调用 write() 是否安全?

language-agnostic - TCP 慢启动、拥塞避免和确定带宽

macos - 如何在 Mac OS X 或 iOS 中以编程方式找到路由器的 IP 地址?