(1) Adjacent octets to be checksummed are paired to form 16-bit
integers, and the 1's complement sum of these 16-bit integers is
formed.
(2) To generate a checksum, the checksum field itself is cleared,
the 16-bit 1's complement sum is computed over the octets
concerned, and the 1's complement of this sum is placed in the
checksum field.
(3) To check a checksum, the 1's complement sum is computed over the
same set of octets, including the checksum field. If the result
is all 1 bits (-0 in 1's complement arithmetic), the check
succeeds.
rfc提到校验和的计算有三个步骤:
- 计算时16位对齐,1's complement 求和(并在最后取反后放进报文)
- 计算前校验和字段清空
- 校验结果应该是全1(取反后全是0)
但是具体什么是1's complement 求和,rfc中似乎并没有的说明,也只是带着提到了一点:
On a 2's complement machine, the 1's complement sum must be
computed by means of an "end around carry", i.e., any overflows
from the most significant bits are added into the least
significant bits. See the examples below.
这里参考 谢希仁的《计算机网路》和最后的rfc代码示例:
1's complement 求和就是二进制求和后,最高位向最低为进位

所以最后的这个取反的过程是不算进 1's complement 求和的,要注意
紧接着,rfc 又提到一些性质:
(下面使用 +‘ 表示 1's complement 求和 , 使用一组 [A, B] 等字母组合表示一个:16位的2进制数,这里要和16进制的A-F区分开,A是高8位,B是低8位,代表的数字就是 A*256 + B)
1. 计算顺序可交换
( [A,B] +' [C,D] +' ... +' [J,0] ) +' ( [0,K] +' ... +' [Y,Z] )
这个就是加法的结合律,没什么
2. 字节序可换(结果也只改变顺序)
[B,A] +' [D,C] +' ... +' [Z,Y]
这里有点思维跳跃的,其实还好理解,比如 [A,B]+[C,D],如果AC有进位,根据反码和的要求,这个进位会传给BD, 同样,BD如果有进位就会传给AC;
字节交换顺序后 [B,A]+[D,C] 的进位方式仍然不变,仍然是BD进位给AC, AC进位给BD,所以最后的结果也只是存在一个字节之间的交换而已。
这里带来的好处就是,当我们收到一个报文时,虽然大端机器和小端机器取出 16 位数据的方式是不一样的,但是字节序可换的性质保证了计算结果并不会影响到,校验时得到的结果是否全是 1, 或者取反全是 0。
除此之外还有多个性质,暂时先不理解,先看一下代码:
check_sum(uint16_t *addr, int count)
{
register long sum = 0;
while( count > 1 ) {
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
checksum = ~sum;
}
因为这个check_sum 中包含了最后的取反,所以在校验端如果仍然是使用这个函数,那正确的结果就会是全零。
最后是奇偶的地方,我觉得还存在一点问题:
sum += * (unsigned char *) addr;
如果最后仍多了一个字节,那么按照在数据最后填充一个全0 的字节来理解的话, 在小端的cpu上 确实是这么写,但是大端cpu 似乎还要再左移8 位。参考谢希仁的《计算机网路》中udp校验的图来看,似乎确实是这样的。
5164

被折叠的 条评论
为什么被折叠?



