IP首部校正和的計算方法: 1.把校正和欄位清零。 2.然後對每16位(2位元組)進行二進位反碼求和,反碼求和的意思是先對每16位求和,再將得到的和轉為反碼。 接下來詳細描述反碼求和的步驟:看下面的代碼 演算法:
SHORT checksum(USHORT* buffer, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum>>16) + (cksum&0xffff);
cksum += (cksum>>16);
return (USHORT)(~cksum);
}
參數buffer是指向16位整數的指標,剛開始指向的是IP首部的起始地址,參數size是IP首部的大小。while迴圈是將IP首部的內容以16位為單元加在一起,如果沒有整除(即size還有餘下的不足16位的部分),則加上餘下的部分,此時的cksum就是相加後的結果,這個結果往往超出了16位,因為校正和是16位的,所以要將高16位和計算得到的cksum再加工。 再加工第一步:cksum = (cksum>>16) + (cksum&0xffff); sum>>16是將高16位移位到低16位,sum&0xffff是取出低16位,相加得到新的cksum。 再加工第二步:cksum += (cksum>>16); 第一步相加時很可能會產生進位,因此要再次把進位移到低16位進行相加。 這樣就加工好了,接下來就是取反,並強制轉換為16位,這樣就得到了最終的校正和。 校正和計算出來了,接下來就是該如何校正: 接收方進行校正時,也是對每16位進行二進位反碼求和。接收方計算校正和時的首部與發送方計算校正和時的首部相比,多了一個發送方計算出來的校正和。因此,如果首部在傳輸過程中沒有發生差錯,那麼接收方計算的結果應該為全一,因為接收方計算除校正和以外的部分得到值是校正和的反碼,再加多出來的校正和當然是全一了。 最後對上述過程舉個例子: IP頭: 45 00 00 31 89 F5 00 00 6E 06 00 00(校正欄位) DE B7 45 5D -> 222.183.69.93 C0 A8 00 DC -> 192.168.0.220 計算: 4500 + 0031 +89F5 + 0000 + 6e06+ 0000 + DEB7 + 455D + C0A8 + 00DC =3 22C4 0003 + 22C4 = 22C7 ~22C7 = DD38 ->即為應填充的校正和 當接受到IP資料包時,要檢查IP頭是否正確,則對IP頭進行檢驗,方法同上: 計算: 4500 + 0031 +89F5 + 0000 + 6E06+ DD38 + DEB7 + 455D + C0A8 + 00DC =3 FFFC 0003 + FFFC = FFFF 得到的結果是全一,正確。