c语言 checksum,容易被忽视的IP报头中的Checksum校验和
看計算機(jī)網(wǎng)絡(luò)相關(guān)的書,每次看到IP或者UDP報頭校驗和時,都一瞥而過,以為相當(dāng)簡單。可是今天一看真傻眼了,怎么算的,為什么用反碼不用補(bǔ)碼還真不知道怎么回事。
算法的C語言實現(xiàn):
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作為一組,當(dāng)成無符號數(shù)相加得到sum,若報頭字節(jié)數(shù)為單數(shù),則最后一個字節(jié)直接當(dāng)8bit無符號數(shù)加到前面的sum上去。
2. 對sum右移16位,并與原sum的低16位相加,得到結(jié)果重新賦給sum。
3. 直到sum的高16位為0時,再將sum取反(反碼),返回sum值作為Checksum。
接收端校驗過程:
接收到的結(jié)果再進(jìn)行一次上述計算,得到返回的值應(yīng)該為0。否則,報頭在傳輸過程中出錯。
解釋1:B + ~B = 2^16 - 1(B 為WORD),算法最后返回的是反碼(反碼求和又叫1的補(bǔ)碼(one'scomplement),而2的補(bǔ)碼就是我們通常說的補(bǔ)碼求和了)。所以接收端收到數(shù)據(jù)報后得到的校驗和為B + ~B(開始校驗和占用的兩個字節(jié)為0,現(xiàn)在更過發(fā)送端的校驗后得到~B) = 2^16 - 1(B 為WORD),返回校驗和的反碼所以就檢查校驗和是否為0即可。
那么為什么用反碼而不用補(bǔ)碼呢?
a.不依賴系統(tǒng)是大端還是小端。即無論你是發(fā)送方計算或者接收方檢查校驗和時,都不需要調(diào)用htons 或者 ntohs,直接通過上面第2節(jié)的算法就可以得到正確的結(jié)果。這個問題你可以自己舉個例子,用反碼求和時,交換16位數(shù)的字節(jié)順序,得到的結(jié)果相同,只是字節(jié)順序相應(yīng)地也交換了;而如果使用原碼或者補(bǔ)碼求和,得到的結(jié)果可能就不相同!比如補(bǔ)碼計算:0xff02 + 0x00ff 和0x02ff + 0xff00結(jié)果是不相同的, 但是對于反碼來說只是序列不同結(jié)果是相同的。
b.計算和驗證校驗和比較簡單,快速。說實話,這個沒怎么看明白,感覺在校驗和計算方面,原碼或者補(bǔ)碼求和反而更簡單一些(從C語言角度),在校驗和驗證上面,通過一樣的算法判斷結(jié)果是否為全0,確實要方便一些,所以可能從綜合考慮確實反碼求和要簡便一些。另外,IP報文在傳輸過程中,路由器經(jīng)常只修改TTL字段(減1),此時路由器轉(zhuǎn)發(fā)該報文時可以直接增加它的校驗和,而不需要對IP整個首部進(jìn)行重新計算。
總結(jié)
以上是生活随笔為你收集整理的c语言 checksum,容易被忽视的IP报头中的Checksum校验和的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHM(prognostics and
- 下一篇: LMD0 (ospid: 8664):