计算机网络通信时,为了检验在数据传输过程中数据是否发生了错误,通常在传输数据的时候连同校验和一块传输,以下简单的程序是数据包的包头中校验和的算法:返回的就是索求的校验和结果,当接收端接受数据时候会从新计算校验和,如果与原校验和不同就视为出错,丢弃该数据包,并返回icmp报文。
在网络传送的数据包为了保证传送正确都含有效验字段,IP、arp、tcp等每
个数据段都有自己的效验和。
效验的计算并不复杂。把相应数据包段的所有数据看成一个字节数组
{a,b,c,d,e},把他们分成16bit一组
{[ab],[cd],[e0]}
计算其和:
[ab]
[cd]
[e0]
--------
[xy]
计算采用循环进位,最高位的进位加到最低位,
如果计算出的[xy]所有位都为1(即为1111 1111)则效验通过。
如果[cd]为效验和的话,已经填好其他各个字节,如何计算出[cd]
(checksum)的值呢?我们首先用0填充[cd],然后算出[xy],则正确的[cd]应该为计
算出的[xy]按位求反的结果。这样才能保证整个数据包段通过效验。
实际程序中,因为现在的机器都是32位的,所以采用变通的算法:
Byte-by-byte "Normal" Swapped
Order Order
Byte 0/1: 00 01 0001 0100
Byte 2/3: f2 03 f203 03f2
Byte 4/5: f4 f5 f4f5 f5f4
Byte 6/7: f6 f7 f6f7 f7f6
--- --- ----- -----
Sum1: 2dc 1f0 2ddf0 1f2dc
dc f0 ddf0 f2dc
Carrys: 1 2 2 1
-- -- ---- ----
Sum2: dd f2 ddf2 f2dd
Final Swap: dd f2 ddf2 ddf2
------------------------------
Byte 0/1/2/3: 0001f203 010003f2 03f20100
Byte 4/5/6/7: f4f5f6f7 f5f4f7f6 f7f6f5f4
-------- -------- --------
Sum1: 0f4f7e8fa 0f6f4fbe8 0fbe8f6f4
Carries: 0 0 0
Top half: f4f7 f6f4 fbe8
Bottom half: e8fa fbe8 f6f4
----- ----- -----
Sum2: 1ddf1 1f2dc 1f2dc
ddf1 f2dc f2dc
Carrys: 1 1 1
---- ---- ----
Sum3: ddf2 f2dd f2dd
Final Swap: ddf2 ddf2 ddf2
可以看到先求32位的checksum,然后将高8位与低八位相加,最终求出的
checksum是相同的。
给出一段C++实现的算法:
in 6
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
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;
}