校驗和的計算方法

2021-07-10 23:30:25 字數 3449 閱讀 7739

校驗和演算法

unsigned short check_sum(unsigned short *addr,int len)

if(nleft==1)

sum=(sum>>16)+(sum&0xffff);

sum+=(sum>>16);

answer=~sum;

return(answer);

}

首先,ip、icmp、udp和tcp報文頭都有檢驗和字段,大小都是16bit,演算法基本上也是一樣的。

在傳送資料時,為了計算資料報的檢驗和。應該按如下步驟:

1、把校驗和字段設定為0;

2、把需要校驗的資料看成以16位為單位的數子組成,依次進行二進位制反碼求和;

3、把得到的結果存入校驗和字段中

在接收資料時,計算資料報的檢驗和相對簡單,按如下步驟:

1、把首部看成以16位為單位的數字組成,依次進行二進位制反碼求和,包括校驗和字段;

2、檢查計算出的校驗和的結果是否為0;

3、如果等於0,說明被整除,校驗和正確。否則,校驗和就是錯誤的,協議棧要拋棄這個資料報。

雖然說上面四種報文的校驗和演算法一樣,但是在作用範圍存在不同:ip校驗和只校驗20位元組的ip報頭;而icmp校驗和覆蓋整個報文(icmp報頭+icmp資料);udp和tcp校驗和不僅覆蓋整個報文,而且還有12個位元組的ip偽首部,包括源ip位址(4位元組)、目的ip位址(4位元組)、協議(2位元組)、tcp/udp包長(2位元組)。另外udp、tcp資料報的長度可以為奇數位元組,所以在計算校驗和時需要在最後增加填充位元組0(填充位元組只是為了計算校驗和,可以不被傳送)。

在udo傳輸協議中,校驗和是可選的,當校驗和字段為0時,表明該udp報文未使用校驗和,接收方就不需要校驗和檢查了!那如果udp校驗和的計算結果是0時怎麼辦?書上有一句話:「如果校驗和的計算結果為0,則存入的值為全1(65535),這在二進位制反碼計算中是等效的」

那麼校驗和到底怎麼計算了?

1、什麼是二進位制反碼求和

對乙個無符號的數,先求其反碼,然後從低位到高位,按位相加,有益處則向高位進1(和一般的二進位制法則一樣),若最高位有進製,則向最低位進1.

首先這裡的反反碼好像和以前學的有符號反碼不一樣,這裡不分正負數,直接每個為都取反。

上面加粗的那句話和我們平時的加法法則不一樣,最高位有進製,則向最低位進1。確實有些疑惑,為什麼要這樣呢?自習分析一下,上面的這種操作,使得在傳送加法進製溢位時,溢位值並不是10000,而是1111.也即是當相加結果滿1111時溢位,這樣也可以說明為什麼0000和1111都表示0了。

下面是兩種二進位制反碼求和的運算:

原碼加法運算:3(0011)+5(0101)=8(1000)

8(1000)+9(1001)=1(0001)

反碼加法運算:3(1100)+5(1010)=8(0111)

8(0111)+9(0110)=2(1101)

從上面的例子中,當加法未發生溢位時,原碼與反碼加法運算結果一樣;當有溢位時,結果就不一樣了,原碼是滿10000溢位,而反碼是滿1111溢位,所以相差正好是1.

另外,關於二進位制反碼求和運算需要說明的一點是,先取反後相加與先相加後取反,得到的結果是一樣的。

2、校驗和演算法實現

**如下:

ushort checksum (ushort *buffer,int size)

unsigned long cksum=0;

while (size>1)

cksum +=*buffer++;

size -=sizeof(ushort);

if (size)

cksum +=*(uchar *) buffer;

//將32位轉換為16位

while (cksum>>16)

cksum = (cksum>>16) + (cksum & 0xffff);

return (ushort) (~cksum);

buffer是指向需要校驗資料緩衝區的指標,size是需要檢驗資料的總長度(位元組為單位)。

4-13行**是對資料按16bit累加求和,由於最高位的進製需要加在最低位上,所以cksum必須是32位的unsigned long型,高16bit用於儲存累加過程中的進製;另外**10~13行是對size為奇數情況的處理。

14~16行**的作用是將cksum高16bit的值加到低16bit上,即把累加中最高位的進製加到最低位上。這裡使用了while迴圈,判斷cksum高16bit是否非零,因為第16行**執行的時候,還是可能向cksum的高16bit進製。

有些地方是通過下面兩條**實現的:

cksum = (cksum >> 16) + (cksum & 0xffff);

cksum = (cksum >> 16);

這裡只進行了兩次相加,即可保證相加後cksum的高16位為0,兩種方式的效果是一樣,事實上,上面的迴圈也最多執行兩次!

17行**即對16bit資料累加的結果取反,得到二進位制反碼求和的結果,然後函式返回該值。

3、為什麼使用二進位制反碼求和呢?

為什麼要使用二進位制反碼來計算校驗和呢,而不是直接使用原碼或者是補碼呢?

上面是原文的一部分,說明在tcp/ip校驗和中使用反碼求和的一些優點:

a、 不依賴系統是大端小端。即無論你是傳送方計算機或者接收方檢查校驗和時,都不要呼叫htons或者ntohs,直接通過上面的演算法就可以得到正確的結果。這個問題你可以自己舉個例子,用反碼求和時,交換16位數的位元組順序,得到的結果相同,只是位元組順序相應地也交換了;而如果使用原碼或者補碼求和,得到的結果可能就不同。

b、 計算和驗證校驗和比較簡單、快遞。

例項:

ip頭: 

45 00 

0031

89 f5 

0000

6e 06 

0000(校驗字段)

de b7 

455d 

-> 

222.183.69.93

c0 a8 

00dc 

-> 

192.168.0.220

計算: 

4500+ 0031 +89f5 + 0000 + 6e06+ 0000 + deb7 + 455d + c0a8 + 00dc =322c4

0003+ 22c4 = 22c7

~22c7 =dd38 

->即為應填充的校驗和

當接受到ip資料報時,要檢查ip頭是否正確,則對ip頭進行檢驗,方法同上:

計算:4500 + 0031+89f5 + 0000 + 6e06+ dd38 + deb7 + 455d + c0a8 + 00dc =3 fffc

0003 + fffc= ffff

~ffff =00000 

->正確

tcp首部檢驗和與ip首部校驗和的計算方法相同,在程式中使用同乙個函式來計算。

校驗和計算方法

1.說明 1 校驗和覆蓋的內容 ip校驗和 ip首部。icmp校驗和 icmp首部 icmp資料 2.計算校驗和的步驟 1 把校驗和字段設定為0。2 把需要校驗的資料看成以16位為單位的數字組成,依次進行二進位制反碼求和。3 把得到的結果存入校驗和字段中。另外udp tcp資料報的長度可以為奇數位元...

IP首部校驗和字段計算方法

ip首部有16bit的校驗和,因此,ip首部以16bit為單位計算校驗和,ip首部的長度一定是16bit的整倍數,這是由於首部長欄位是以32bit為單位計算的,不足的補0。傳送方計算方法 1.首先把校驗和的16bit置0。2.將首部以16bit為單位異或 或模2加,結果相同 3.將異或結果取反,並填...

IP和TCP包頭校驗和計算方法

出處 校驗和的演算法 將資料以字為單位累加到乙個雙字中,如果資料長度為奇數,最後乙個位元組要先變成字,然後在加到原來的雙字中,最後得到的結果是乙個雙字,最後將這個雙字的高16位和低16位反覆相加,直到高16位為0,從而就獲得乙個16位的值,再將這個16位的值取反就得到校驗和的值了。在接收端接收到ip...