一開始,私以為校驗和只是簡單的求和得到的結果,后來在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;
測試結果:

可見,二進制反碼求和與字節序無關。
