现在的位置: 首页 > 综合 > 正文

IP校验和计算纠结

2013年02月04日 ⁄ 综合 ⁄ 共 1613字 ⁄ 字号 评论关闭

下面摘自《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

抱歉!评论已关闭.