Chinaunix首页 | 论坛 | 博客
  • 博客访问: 121986
  • 博文数量: 41
  • 博客积分: 2564
  • 博客等级: 少校
  • 技术积分: 455
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-20 19:17
文章分类

全部博文(41)

文章存档

2009年(41)

我的朋友

分类: C/C++

2009-04-20 11:43:20

相信很多人看了《TCP/IP详解 卷一:协议》3.2中关于IP检验和的计算方法后,就会去试一下,但是发现计算出来的值是错误的。这是为什么呢,其实是对书中所阐述的方法理解不到位的原因。书中的原话(中文):

“为了计算一份数据报的IP检验和,首先把检验和字段置为0。然后,对首部中每个16 bit进行二进制反码求和(整个首部看成是由一串 16 bit的字组成),结果存在检验和字段中。当收到一份I P数据报后,同样对首部中每个16 bit进行二进制反码的求和”

很多人在计算的时候,采用的方法往往是这样:

·csum类型为unsigned long,并置为0

·每次取首部16 bit(即一个unsigned short),与csum相加,直到取完(若首部长度为奇数则最后一次取的时候,高8位补零)

·csum取反

·返回csum的低16位(或将csum转化为unsgined short返回)

这样的做法是错误的,因为这样做可能会丢失了一些数据————csum的高16位。下面是网络上流行的算法:

USHORT checksum(USHORT *buffer, int size)
{
    unsigned long cksum=0;
    while(size >1)
   {
        cksum+=*buffer++;
        size -=sizeof(USHORT);
    }
    if(size ) cksum += *(UCHAR*)buffer;
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (USHORT)(~cksum);
}

这个算法是正确的,关键的地方就是最后2句!(注意,这里使用了一个技巧,取反求和等于求和取反)。最后两句是为了防止数据丢失,也就是将求和的结果cksum的高16位与低16位相加。至于为什么执行两次,而不是3次或更多,看下面的例子:

·cksum计算完后(最后2句之前),值为0x3ffff

·执行cksum = (cksum >> 16) + (cksum & 0xffff)得:0x10002

·依然超过16位,因此需要cksum += (cksum >>16),不会有第3次了

看这个算法之后,我对书中描述的新理解:

·对首部中每个16 bit进行二进制反码求和

·将每次计算的结果添加到剩余的IP首部二进制序列中(以16 bit为单位),这步很重要!

·重复1、2步,直到IP首部二进制序列剩下16bit

举例,假设一个IP首部为:

#初始状态

45 00 00 2e
be 55 00 00
7a 11 00 00<----检验和置为0
de b7 7e e3
c0 a8 12 7a

#第1轮

45 2e be 55

00 00 7a 11

00 00 de b7

7e e3 c0 a8

12 7a

#第2轮

00 01 03 83<----此为452e + be55的结果

00 00 7a 11

00 00 de b7

7e e3 c0 a8

12 7a

#第3轮

03 84 00 00

7a 11 00 00

de b7 7e e3

c0 a8 12 7a

#第4轮

03 84 7a 11

00 00 de b7

7e e3 c0 a8

12 7a

#第5轮

7d 95 00 00

de b7 7e e3

c0 a8 12 7a

#第6轮

7d 95 de b7

7e e3 c0 a8

12 7a

#第7轮

00 01 5c 4c

7e e3 c0 a8

12 7a

#第8轮

5c 4d 7e e3

c0 a8 12 7a

#第9轮

db 30 c0 a8

12 7a

#第10轮

00 01 9b d8

12 7a

#第11轮

9b d9 12 7a

#第12轮

ae 53

#取反

51ac

则这个IP包的校验和就是51ac。

当然,在编程实现的时候不必那么多步骤,先将结果存入一个32位的整形数,最后再将高16位与低16为相加(2次)即可。

阅读(7380) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~