TCP頭校驗和計算算法詳解


我就不管是按“位”( bit)取反相加,還是 按“1的補碼”相加了,總之
就是把需要進行校驗的“字串”加( +)起來,把這相加的 結果取反當做
校驗和” ( Checksum), 比如,相加的結果是 0101,那么“ 校驗和”就
1010,驗證的時候呢,就是  0101+1010 = 1111 ,取反后, 就是 0
——如果驗證得“零”( 0),就是正確的!

先將checksum字段置零,然后按16位分組,計算2進制反碼和,最后再求和的反碼!

為了計算一份數據報的IP檢驗和,首先把檢驗和字段置為0。然后,對首部中每個16bit進行二進制反碼求和(整個首部看成是由一串16bit的字組成),結果存在檢驗和字段中。當收到一份IP數據報后,同樣對首部中每個16bit進行二進制反碼的求和。由於接收方在計算過程中包含了發送方存在首部中的檢驗和,因此,如果首部在傳輸過程中沒有發生任何差錯,那么接收方計算的結果應該為全1。如果結果不是全1(即檢驗和錯誤),那么IP就丟棄收到的數據報。但是不生成差錯報文,由上層去發現丟失的數據報並進行重傳。


當發送IP包時,需要計算IP報頭的校驗和:

1、  把校驗和字段置為0;

2、  對IP頭部中的每16bit進行二進制求和;

3、  如果和的高16bit不為0,則將和的高16bit和低16bit反復相加,直到和的高16bit為0,從而獲得一個16bit的值;

4、  將該16bit的值取反,存入校驗和字段。

◆當接收IP包時,需要對報頭進行確認,檢查IP頭是否有誤,算法同上2、3步,然后判斷取反 的結果是否為0,是則正確,否則有錯。

 

算法:

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);  //將高16bit與低16bit相加

cksum += (cksum>>16);             //將進位到高位的16bit與低16bit 再相加

 

return (USHORT)(~cksum);

}

 

 

實例:

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

     ~FFFF = 00000     ->正確

TCP首部檢驗和與IP首部校驗和的計算方法相同,在程序中使用同一個函數來計算。

需要注意的是,由於TCP首部中不包含源地址與目標地址等信息,為了保證TCP校驗的有效性,在進行TCP校驗和的計算時,需要增加一個TCP偽首部的校驗和,定義如下:

struct 

{

unsigned long saddr; //源地址

unsigned long daddr; //目的地址

char mbz;//置空

char ptcl; //協議類型

unsigned short tcpl; //TCP長度

}psd_header;

 



然后我們將這兩個字段復制到同一個緩沖區SendBuf中並計算TCP校驗和:

memcpy(SendBuf,&psd_header,sizeof(psd_header)); 

memcpy(SendBuf+sizeof(psd_header),&tcp_header,sizeof(tcp_header));

tcp_header.th_sum=checksum((USHORT *)SendBuf,sizeof(psd_header)+sizeof(tcp_header));

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM