IP校验和计算
下面摘自《TCP/IP协议簇》的IP头校验和算法:
发送时:
1. 将校验和字段置为0;
2. 将整个首部分为16bit的部分,求和;
3. 取反码,填入到校验和字段中;
接收时:
1. 直接将整个首部分为16bit的部分,求和;
2. 取反码,若结果为0,取合法;否则丢弃;
这上面有两个细节没有描述清楚:
1. 计算时的字节顺序(litter endian和big endian)问题;
2. 取和溢出时的改进计算方法;
根据实验结果,及参考网络上的资料,实际上几乎现有所有的系统对校验和算法已经有点小小的补充,也许《TCP/IP协议簇》这里没有更新罢了,自我安慰吧,如下:
◆当发送IP包时,需要计算IP报头的校验和:
1、 把校验和字段置为0;
2、 对IP头部中的每16bit进行二进制求和;
3、 如果和的高16bit不为0,则将和的高16bit和低16bit反复相加,直到和的高16bit为0,从而获得一个16bit的值;
4、 将该16bit的值取反,存入校验和字段。
◆当接收IP包时,需要对报头进行确认,检查IP头是否有误,算法同上2、3步,然后判断取反的结果是否为0,是则正确,否则有错。
算法:
unsigned short CheckSum(unsigned short *_pBuff, int _Size)
{
unsigned int ckSum = 0;
unsigned short *tmpBuff = _pBuff;
int tmpSize = _Size;
while (tmpSize > 1)
{
ckSum += *tmpBuff ++;
tmpSize -= sizeof(unsigned short);
}
if (tmpSize > 0)
{
ckSum += *(unsigned char*)tmpBuff;
}
ckSum = (ckSum >> 16) + (ckSum & 0xFFFF); //将高16bit与低16bit相加
ckSum += (ckSum >> 16); //将进位到高位的16bit与低16bit 再相加
return (unsigned short)(~ckSum);
}
关于计算时的字节顺序,一般以网络字节顺序(big endian)为准,但仍然有个十分模糊的地方,就是为什么校验和这个字段不用进行网络转换了,如X86系统,直接以本地字节顺序(litter endian)发送就可以了,这也让我十分纠结。
下面是举例:
char szBuf[] = {'\x45', '\x00', '\x00', '\xf4', '\x00', '\x2e', '\x00', '\x00' ,'\x80' ,'\x11',
'\x00', '\x00', '\xc0', '\xa8', '\x09', '\x0a', '\xc0', '\xa8', '\x09', '\xff'};
unsigned short SendCkSum = 0x71a5; //这个值不用转换为网络字节顺序,直接以 A5 71填入
char szBuf[] = {'\x45', '\x00', '\x00', '\xf4', '\x00', '\x2e', '\x00', '\x00' ,'\x80' ,'\x11',
'\xa5', '\x71', '\xc0', '\xa8', '\x09', '\x0a', '\xc0', '\xa8', '\x09', '\xff'};
unsigned short RecvCkSum = CheckSum((unsigned short*)szBuf, 20); //这里RecvCkSum为0
---------------------------------------------------------------------------
低调的python小子
当梦想照进现实 幸福近在咫尺
[jpg]http://ip.ipwind.cn/msn.png[/jpg]