一开始,私以为校验和只是简单的求和得到的结果,后来在TCP和UDP里面看到使用的校验和方式有点奇怪--二进制反码(循环进位)求和。
人类的认知过程必将从简单到复杂,看下这个二进制反码循环求和是啥子意思。以16进制示例:
1.对校验序列word1,word2...wordn的二进制表示求反码
2.对求的反码序列循环进位求和,循环进位求和的意思是指把求和的进位加到低位,可能进位有x位,把这x位表示的数字和求和结果的16位相加。
感觉好像变复杂了。没关系,二进制反码循环进位求和有以下特性:
1.求和过程先求反码再二进制循环进位求和等价于先二进制循环进位求和再对求和结果求反码。(如此大大减少求反码的次数)
2.与字节序(大端小端问题)无关。(这也许是许多协议使用这种方式求和的原因)
1 ///@func:To caculate the Checksum of data 2 ///@param: 1.nums :the number of sizeof(unsigned short int) 3 /// 4 unsigned short int WordCheckSum(const unsigned short int *data, unsigned short int nums) 5 { 6 short int index = 0; 7 unsigned int sum = 0; 8 unsigned short int checkSum ; 9 for (index = 0; index < nums;index++) 10 { 11 sum += data[index]; 12 } 13 //cout << "the sum of data is: " << hex << sum << endl; 14 checkSum = (unsigned short int)(sum & 0xffff)+(unsigned short int)(sum >> 16) ; 15 /*cout << "the checkSum of data is: " << checkSum << endl;*/ 16 return ~checkSum; 17 }
测试代码:
WORD data1[5] = { 0x1122, 0x1122, 0x1122, 0x1122, 0x1122 }; WORD data2[5] = { 0x2211, 0x2211, 0x2211, 0x2211, 0x2211 }; cout << "the CheckSum of data1 is: " << hex << WordCheckSum(data1, 5) << endl; cout << "the CheckSum of data2 is: " << hex << WordCheckSum(data2, 5) << endl;
测试结果:
可见,二进制反码求和与字节序无关。