关于IP数据包首部校验字段的理解
IP数据包格式及首部个字段:
www.2cto.com
www.2cto.com
![](http://up.2cto.com/2013/0314/20130314113928897.jpg)
对上表的各个数据项就不一一解释了,这里具体关注以下几个数据项:
1、4位首部长度:这里的长度指的是4Bytes单元的个数,例如上图在“选项”字段不存在的情况下,IP包的首部是20Bytes,那么首部长度字段应该为5。另外根据首部长度的位数,也可以得知IP数据包的首部最长为:(2^4 - 1) * 4 = 60 Bytes,当然这个不常用,为了减少开销IP数据包的首部一般为20 Bytes.
2、16位总长度:整个IP数据包的长度,字节为单位,很显然可以利用总的数据包的长度减去数据包的首部长度可以得到IP数据数据包中数据内容的长度,同理可以得知IP数据包的MAX_LENGTH为65535 Bytes,这个字段是IP首部必要的内容。
3、16位首部校验和:
steve的书上是这样说的:
a、把校验和字段置零
b、对首部中每个16位进行二进制反码求和(整个首部看成是由一串16BIT的字组成),结果存在校验和字段中。
c、收到一份IP数据报后,同样对首部的每个16bit进行二进制反码求和(高位溢出添加到低位,与通常的补码运算直接丢弃溢出的高位不同)。
d、接收方在计算过程中包含了发送方存在的首部校验和,因此,首部在发送过程中如果没有任何差错,那么接收方计算的检验结果应该全为1(0xFFFF),否则表明数据包接收错误,丢弃该IP包。
注意:这里的二进制反码求和理解应该为对各个16Bbit进行求和后取反,关键是这些16bit的单元加在一起,如果没有整除16(size还存在不足16位),则应该加上剩余的部分,这是的结果应该会超出16位,所以要对高出16位的的和再次与低16位相加得到cksum,这是第一步。而第一步相加是很可能会再次产生进位,因此需要再次把进位移到低16位相加的到最终的cksum的反码,这是将结果取反即可。
下面还是通过TEST SOURCE CODE来仔细了解该过程:
通用的校验函数:
![](http://up.2cto.com/2013/0314/20130314113929477.jpg)
Main函数中调用:
![](http://up.2cto.com/2013/0314/20130314113929658.jpg)
从理论上判断,如果对接收的IP包中的校验值再次重新校验一次,在数据包准确无误的情况下,得出的新的校验值应该是0XFFFF(当然,计算机用补码在计算,可能显示的结果是0),其他的结果表示接收到的数据包有错误。故cksum 2应该为0, cksum 3应该与cksum 1相同。
这里验证过:
![](http://up.2cto.com/2013/0314/20130314113930502.jpg)
IP数据包中的首部校验字段的算法不采用循环冗余算法,是因为IP包在网络中传输时,其TTL字段的值经常会变化,故采用简单的叠加方法,就可以避开中间 路由器重新计算其校验值,只是简单的增加1操作即可,这样可以明显提高传输效率。