c语言 checksum,容易被忽视的IP报头中的Checksum校验和
看計算機網絡相關的書,每次看到IP或者UDP報頭校驗和時,都一瞥而過,以為相當簡單。可是今天一看真傻眼了,怎么算的,為什么用反碼不用補碼還真不知道怎么回事。
算法的C語言實現:
unsignedshortcsum(unsignedchar *addr,intcount)
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register long sum = 0;
while( count > 1 ) {
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
checksum = ~sum;
return checksum;
}
計算校驗和的算法思路:
1. 將原Checksum位置全部置0,把報頭中每16bit作為一組,當成無符號數相加得到sum,若報頭字節數為單數,則最后一個字節直接當8bit無符號數加到前面的sum上去。
2. 對sum右移16位,并與原sum的低16位相加,得到結果重新賦給sum。
3. 直到sum的高16位為0時,再將sum取反(反碼),返回sum值作為Checksum。
接收端校驗過程:
接收到的結果再進行一次上述計算,得到返回的值應該為0。否則,報頭在傳輸過程中出錯。
解釋1:B + ~B = 2^16 - 1(B 為WORD),算法最后返回的是反碼(反碼求和又叫1的補碼(one'scomplement),而2的補碼就是我們通常說的補碼求和了)。所以接收端收到數據報后得到的校驗和為B + ~B(開始校驗和占用的兩個字節為0,現在更過發送端的校驗后得到~B) = 2^16 - 1(B 為WORD),返回校驗和的反碼所以就檢查校驗和是否為0即可。
那么為什么用反碼而不用補碼呢?
a.不依賴系統是大端還是小端。即無論你是發送方計算或者接收方檢查校驗和時,都不需要調用htons 或者 ntohs,直接通過上面第2節的算法就可以得到正確的結果。這個問題你可以自己舉個例子,用反碼求和時,交換16位數的字節順序,得到的結果相同,只是字節順序相應地也交換了;而如果使用原碼或者補碼求和,得到的結果可能就不相同!比如補碼計算:0xff02 + 0x00ff 和0x02ff + 0xff00結果是不相同的, 但是對于反碼來說只是序列不同結果是相同的。
b.計算和驗證校驗和比較簡單,快速。說實話,這個沒怎么看明白,感覺在校驗和計算方面,原碼或者補碼求和反而更簡單一些(從C語言角度),在校驗和驗證上面,通過一樣的算法判斷結果是否為全0,確實要方便一些,所以可能從綜合考慮確實反碼求和要簡便一些。另外,IP報文在傳輸過程中,路由器經常只修改TTL字段(減1),此時路由器轉發該報文時可以直接增加它的校驗和,而不需要對IP整個首部進行重新計算。
總結
以上是生活随笔為你收集整理的c语言 checksum,容易被忽视的IP报头中的Checksum校验和的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHM(prognostics and
- 下一篇: LMD0 (ospid: 8664):