IP TCP UDP ICMP IGMP检验和的计算方法

IP TCP UDP ICMP IGMP检验和的计算方法

 

 

为了计算一份数据报的IP检验和,首先把检验和字段置为0。然后,对首部中每个16bit进
行二进制反码求和(整个首部看成是由一串16bit的字组成),结果存在检验和字段中。
当收到一份IP数据报后,同样首部中每个16bit进行反码求和。由于接收方在计算过程中
包含了发送方存在首部中的检验和,因为如果首部在传输过程中没有发生任何差错,那么
接收方计算的结果应该为全1。如果结果不是1(即检验和错误),那么IP就丢弃收到的数
据报。

这是TCP/IP中的原文

 

定理1:原码+反码=value1    则value1的二进制全为1
定理2:相加后取反=取反后相加

 

发送时,把检验和字段清0,然后按“二进制反码求和”方式计算,最后填入的是检验和字段。

接收时,检验和字段不变,按“二进制反码求和”方式计算,如果传输不存在错误,则结果必然为0。因为定理1

 

在IP TCP UDP ICMP IGMP数据首部中,都有一个检验和字段,这几个协议都使用相同的算法来计算检验和,在《TCP/IP详解》这本书中对算法的描述不是太清晰,现在以IP协议为例,说明一下计算方法。

 

发送端的计算方法:

  1. 将IP首部中的检验和字段全部置0
    检验和字段长16bit
  2. 把IP首部以16bit为单位分成若干组
    现在IP首部被分成了若干组16bit长的数据
  3. 将这若干个16bit长的数据相加
    这里采用循环进位,将最高位第16位的进位加到最低位第1位上,如:1000 0000 0000 0000+1000 0000 0000 0000=1 0000 0000 0000 0000,这里第16位相加时发生了进位,1处于第17位,这个1应该进位到最低位第1位上,结果应该是1000 0000 0000 0000+1000 0000 0000 0000=0000 0000 0000 0001
  4. 所有16bit相加后取反就得到了检验和
    如:1011 0110 1111 1010取反就是0100 1001 0000 0101

用例子验证一下:

在计算机上随便捕获了一个IP数据报(在windows系统上捕获网络流量可以使用Microsoft Network Monitor),IP首部如下:

每一行长32bit,后面是2进制对应的16进制

0100 0101 0000 0000 0000 0101 1100 1000 | 4500 05C8

1100 0000 0101 1100 0100 0000 0000 0000 | C05C 4000

0011 0101 0000 0110 0101 1010 0110 0001 | 3506 5A61

0111 1001 0000 1110 1110 1011 1010 0110 | 790E EBA6

1100 0000 1010 1000 0000 0000 0001 0101 | C0A8 0015

先解释一下各行的含义(按各字段排列顺序):

第一行:4bit版本、4bit首部长度、8bit服务类型、16bit IP数据报总长度

第二行:16bit标识、3bit标志、13bit片偏移

第三行:8bit生存时间TTL、8bit协议类型、16bit首部检验和

第四行:32bit源IP地址

第五行:32bit目的IP地址

 

第三行的低16位5A61是已经计算出来的检验和,在我们计算时要将这16bit置0,下面的计算用16进制代替2进制,比较好记

第一行:4500+05C8=4AC8

第二行:C05C+4000=005D

第三行:3506+0000=3506 计算时要把检验字段全部置0

第四行:790E+EBA6=64B5

第五行:C0A8+0015=C0BD

 

将各行结果再相加:

4AC8+005D+3506+64B5+C0BD=A59E

2进制形式是:1010 0101 1001 1110

将相加的最终结果取反就得到了:5A61

2进制形式是:0101 1010 0110 0001

与IP首部中的检验和完全相同。

 

另外,用16进制计算比较快,容易记。还可以将这些16进制组(每组长16bit)一起相加后再进位,结果是一样的

 

 

看一些网络程序的源码时,发现几乎都是用同一种程序来计算检验和的:

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);
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值