校验和算法分析【转】



        另外关于二进制反码求和运算需要说明的一点是,先取反后相加与先相加后取反,得到的结果是一样的!(事实上我们的编程算法里,几乎都是先相加后取反。)

2. 校验和算法的实现


讲了什么是二进制反码求和,那么校验和的算法实现就简单多了。废话少说,直接上代码:

[cpp]view plaincopy

 

1        //计算校验和 

2        USHORT checksum(USHORT *buffer,int size) 

3        

4            unsigned long cksum=0; 

5            while(size>1) 

6            { 

7                cksum+=*buffer++; 

8                size-=sizeof(USHORT); 

9            } 

10          if(size) 

11          { 

12              cksum+=*(UCHAR *)buffer; 

13          } 

14          //32位数转换成16 

15          while (cksum>>16) 

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

17          return (USHORT) (~cksum); 

18      

buffer是指向需校验数据缓存区的指针,size是需校验数据的总长度(字节为单位)

4~13行代码对数据按16bit累加求和,由于最高位的进位需要加在最低位上,所以cksum必须是32bitunsigned long,高16bit用于保存累加过程中的进位;另外代码10~13行是对size为奇数情况的处理!

14~16行代码的作用是将cksum16bit的值加到低16bit上,即把累加中最高位的进位加到最低位上。这里使用了while循环,判断cksum16bit是否非零,因为第16行代码执行的时候,仍可能向cksum的高16bit进位。

有些地方是通过下面两条代码实现的:

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

这里只进行了两次相加,即可保证相加后cksum的高16位为0,两种方式的效果一样。事实上,上面的循环也最多执行两次!

17行代码即对16bit数据累加的结果取反,得到二进制反码求和的结果,然后函数返回该值。


3. 为什么使用二进制反码求和呢?

        好了,最后一个问题,为什么要使用二进制反码来计算校验和呢,而不是直接使用原码或者补码?

这个问题我想了很久,由于水平有限实在弄不明白,于是在百度上一阵狂搜,什么都没有(不知道是百度不给力,还是大家都不关注这个问题呢?)。果断换google,敲了3个关键词:why checksum tcp,嘿嘿结果第二篇就是我想要的文章了!!!

先把链接给大家吧:http://www.netfor2.com/checksum.html

这篇文章主要介绍二进制反码求和(the 1's complement sum)与补码求和(the 2's complement sum)的区别,另外还说明了在TCP/IP校验和中使用反码求和的优点。

It may look awkword to use a 1'scomplement addition on 2's complement machines. This method however has its ownbenefits.

Probably the most important is that itis endian independent. Little Endian computers store hex numbers with the LSBlast (Intel processors for example). Big Endian computers put the LSB first(IBM mainframes for example). When carry is added to the LSB to form the 1'scomplement sum (see the example) it doesn't matter if we add 03 + 01 or 01 +03. The result is the same.

Other benefits include the easiness of checking the transmission and the checksum calculation plus a variety of ways to speed up the calculation by updating only IP fields that have changed.

       上面是原文的一部分,说明TCP/IP校验和中使用反码求和的一些优点:

        a.不依赖系统是大端还是小端。即无论你是发送方计算或者接收方检查校验和时,都不需要调用htons 或者 ntohs,直接通过上面第2节的算法就可以得到正确的结果。这个问题你可以自己举个例子,用反码求和时,交换16位数的字节顺序,得到的结果相同,只是字节顺序相应地也交换了;而如果使用原码或者补码求和,得到的结果可能就不相同!

        b.计算和验证校验和比较简单,快速。说实话,这个没怎么看明白,感觉在校验和计算方面,原码或者补码求和反而更简单一些(从C语言角度),在校验和验证上面,通过一样的算法判断结果是否为全0,确实要方便一些,所以可能从综合考虑确实反码求和要简便一些。另外,IP报文在传输过程中,路由器经常只修改TTL字段(减1),此时路由器转发该报文时可以直接增加它的校验和,而不需要对IP整个首部进行重新计算。当然,可能从汇编语言的角度看,反码求和还有很多高效的地方,这里就不在深入追究了~~~


结语:本来一个不怎么注意的地方,深入探究一下竟然发现这么多东西。学习算法其实没有必要抱着《算法导论》一页一页地啃(嘿嘿,哥也有一本哦),我更喜欢从TCP/IP协议或LInux内核原理中去探究算法以及实现思想,这样反倒更有趣,而且这里面的一些算法和思想相当经典,慢慢体会,必然受益匪浅!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值