當傳送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)
if(size)
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
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));
====
--------
網路資料報效驗和(checksum)的計算
在網路傳送的資料報為了保證傳送正確都含有效驗字段,ip、arp、tcp等每
個資料段都有自己的效驗和。
效驗的計算並不複雜。把相應資料報段的所有資料看成乙個位元組陣列
,把他們分成16bit一組
計算其和:
[ab]
[cd]
[e0]
--------
[xy]
計算採用迴圈進製,最高位的進製加到最低位,
如果計算出的[xy]所有位都為1(即為1111 1111)則效驗通過。
如果[cd]為效驗和的話,已經填好其他各個位元組,如何計算出[cd]
(checksum)的值呢?我們首先用0填充[cd],然後算出[xy],則正確的[cd]應該為計
算出的[xy]按位求反的結果。這樣才能保證整個資料報段通過效驗。
實際程式中,因為現在的機器都是32位的,所以採用變通的演算法:
byte-by-byte
order
order
byte 0/1:
00 01
0001
0100
byte 2/3:
f2 03
f203
03f2
byte 4/5:
f4 f5
f4f5
f5f4
byte 6/7:
f6 f7
f6f7
f7f6
--- ---
-----
-----
sum1:
2dc 1f0
2ddf0
1f2dc
dc f0
ddf0
f2dc
carrys:
1 2
2 1
-- --
----
----
sum2:
dd f2
ddf2
f2dd
final swap: dd
f2 ddf2
ddf2
------------------------------
byte 0/1/2/3: 0001f203
010003f2
03f20100
byte 4/5/6/7: f4f5f6f7
f5f4f7f6
f7f6f5f4
--------
--------
--------
sum1:
0f4f7e8fa
0f6f4fbe8
0fbe8f6f4
carries:
0 0
0 top half:
f4f7
f6f4
fbe8
bottom half:
e8fa
fbe8
f6f4
-----
-----
-----
sum2:
1ddf1
1f2dc
1f2dc
ddf1
f2dc
f2dc
carrys:
1 1
1 ----
----
----
sum3:
ddf2
f2dd
f2dd
final swap:
ddf2
ddf2
ddf2
可以看到先求32位的checksum,然後將高8位與低八位相加,最終求出的
checksum是相同的。
給出一段c++實現的演算法:
in 6
/* 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;
}====
TCP頭校驗和計算演算法詳解
我就不管是按 位 bit 取反相加,還是 按 1的補碼 相加了,總之 就是把需要進行校驗的 字串 加 起來,把這相加的 結果取反當做 校驗和 checksum 比如,相加的結果是0101,那麼 校驗和 就 是1010,驗證的時候呢,就是0101 1010 1111,取反後,就是0 如果驗證得 零 0...
C 計算ICMP頭的校驗和例項
複製 如下 ushort checksum ushort buff,int nsize 程式設計客棧 如果為奇數,將最後乙個字擴充套件到雙字,再累加 www.cppcns.comnbsp if nsize nbs 將cksum的高16位與低16位相加,取反後得到校驗和 cksum cksum 16 ...
IP和TCP包頭校驗和計算方法
出處 校驗和的演算法 將資料以字為單位累加到乙個雙字中,如果資料長度為奇數,最後乙個位元組要先變成字,然後在加到原來的雙字中,最後得到的結果是乙個雙字,最後將這個雙字的高16位和低16位反覆相加,直到高16位為0,從而就獲得乙個16位的值,再將這個16位的值取反就得到校驗和的值了。在接收端接收到ip...