This question already has answers here:
Bit shifting in internet checksums

(3 个回答)


4年前关闭。




我正在努力理解为什么 ICMP 校验和总数(在被补充之前)是 this line of code 中的总数 + 右移 16 位总数:
checksum bs = let bs' = (if (BL.length bs) `mod` 2 == 0 then bs else BL.snoc bs 0)
                  ws = runGet listOfWord16 bs'
                  total = sum (map fromIntegral ws) :: Word32
              in complement (fromIntegral total + fromIntegral (total `shiftR` 16))

RFC 792 关于计算校验和有这样的说法:



我理解为什么要计算 bs',因为“如果总长度为奇数,则接收到的数据将填充一个八位字节的零以计算校验和。”

我也可以理解对这行代码 total = sum (map fromIntegral ws) :: Word32 中完成的 16 位字的总和进行求和

我只是无法弄清楚为什么在这行代码中:
complement (fromIntegral total + fromIntegral (total `shiftR` 16))
+ fromIntegral (total `shiftR` 16) 应该包括在内。

注意:我已经使用wireshark 验证了校验和只有在我像链接的代码行中所做的那样补充 total + total `shiftR` 16 时才正确。所以我知道这是正确的,我只是不明白为什么。

最佳答案

RFC 1071 详细描述了校验和定义,包括这个重要部分:



在您的代码中,

total = sum (map fromIntegral ws) :: Word32

是 32 位和,即它的低 16 位是没有进位的和,高 16 位将包含进位的和。通过使用 fromIntegral :: Word32 -> Word16 进行截断的事实,我们有
low = fromIntegral total :: Word16
high = fromIntegral $ total `shiftR` 16 :: Word16

所以我们可以计算“结束进位”为
eac = low + high

关于haskell - 为什么 ICMP 校验和移位 16 位,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44815097/

10-16 19:16