网络ip地址的头部校验和的理解

原文:http://hi.baidu.com/zengzhaonong/item/6d194fd9d28de63f49e1dd7b

 

在发送数据时,为了计算数IP据报的校验和。应该按如下步骤:
(1) 把IP数据报的校验和字段置为0。
(2) 把首部看成以16位为单位的数字组成,依次进行二进制反码求和
(3) 把得到的结果存入校验和字段中。

在接收数据时,计算数据报的校验和相对简单,按如下步骤:
(1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段。
(2)检查计算出的校验和的结果是否等于零。
(3) 如果等于零,说明被整除,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。

是用C语言编写的。许多实现网络协议栈的代码,这个算法是最常用的了,即使变化,也无非是先取反后取和之类的。考虑其原因,估计还是C语言的移植性更好吧。下面是该函数的实现:
unsigned short checksum(unsigned short *buf, int nword)
{
    unsigned long sum;

    for(sum = 0; nword > 0; nword--)
        sum += *buf++;

    sum = (sum>>16) + (sum&0xffff);
    sum += (sum>>16);

    return ~sum;
}
让我们假设一个IP头数据,来解cksum的惑
说明:上面算法是先进行加法运算,然后再进行求反。: 而这个求和过程也包括检验和字段

01000101                             /*ver_hlen*/
00000000                             /*tos*/
00000000 00000010                    /*len*/
00000000 00000000                    /*id*/
00000000 00000000                    /*offset*/
00000100                             /*ttl*/
00010001                             /*type*/
00000000 00000000                    /*cksum(0)*/
01111111 00000000 00000000 00000001 -/*sip*/
01111111 00000000 00000000 00000001 -/*dip*/

运算过程(注意是大端格式加):
for(sum = 0; nword > 0; nword--)
    sum += *buf++;

-01000101 00000000
-00000000 00000010
---------------------
-01000101 00000010
-00000000 00000000
---------------------
-01000101 00000010
-00000000 00000000
---------------------
-01000101 00000010
-00000100 00010001
---------------------
-01001001 00010011
-00000000 00000000
---------------------
-01001001 00010011
-01111111 00000000
---------------------
-11001000 00010011
-00000000 00000001
---------------------
-11001000 00010100
-01111111 00000000
---------------------
101000111 00010100
-00000000 00000001
---------------------
101000111 00010101            sum

                
sum = (sum>>16) + (sum&0xffff);
00000000 00000001            (sum>>16)
01000111 00010101            (sum&0xffff)
---------------------
01000111 00010110

sum += (sum>>16);
01000111 00010110
00000000 00000000            (sum>>16)
---------------------
01000111 00010110            sum

~sum
10111000 11101001            cksum  
      
说白了就是循环加,然后在取反!



对方机器调用checksum()计算校验和,如果校验和为0表明IP包传输正确
-----------------------------------------------------------
01000101                             /*ver_hlen*/
00000000                             /*tos*/
00000000 00000010                    /*len*/
00000000 00000000                    /*id*/
00000000 00000000                    /*offset*/
00000100                             /*ttl*/
00010001                             /*type*/
10111000 11101001                    /*cksum(0)*/
01111111 00000000 00000000 00000001 /*sip*/
01111111 00000000 00000000 00000001 /*dip*/

-01000101 00000000
-00000000 00000010
---------------------
-01000101 00000010
-00000000 00000000
---------------------
-01000101 00000010
-00000000 00000000
---------------------
-01000101 00000010
-00000100 00010001
---------------------
-01001001 00010011
- 10111000 11101001
---------------------
100000001 11111100
-01111111 00000000
---------------------
110000000 11111100
-00000000 00000001
---------------------
110000000 11111101
-01111111 00000000
---------------------
111111111 11111101
-00000000 00000001
---------------------
111111111 11111110            sum

sum = (sum>>16) + (sum&0xffff);
00000000 00000001            (sum>>16)
11111111 11111110            (sum&0xffff)
----------------------
11111111 11111111

sum += (sum>>16);
11111111 11111111
00000000 00000000            (sum>>16)
----------------------
11111111 11111111

~sum
00000000 00000000


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值