❶ IP/UDP/TCP/ICMP數據報協議的校驗和的區別和計算
首先,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位元組,第一位元組補0)和TCP/UDP包長(2位元組)。另外UDP、TCP數據報的長度可以為奇數位元組,所以在計算校驗和時需要在最後增加填充位元組0(注意,填充位元組只是為了計算校驗和,可以不被傳送)。
這里還要提一點,UDP的校驗和是可選的,當校驗和欄位為0時,表明該UDP報文未使用校驗和,接收方就不需要校驗和檢查了!那如果UDP校驗和的計算結果是0時怎麼辦呢?書上有這么一句話:「如果校驗和的計算結果為0,則存入的值為全1(65535),這在二進制反碼計算中是等效的。」
講了這么多,那這個校驗和到底是怎麼算的呢?
1. 什麼是二進制反碼求和
對一個無符號的數,先求其反碼,然後從低位到高位,按位相加,有溢出則向高位進1(跟一般的二進制加法規則一樣),若最高位有進位,則向最低位進1。
首先這里的反碼好像跟我們以前學的有符號數的反碼不一樣(即正數的反碼是其本身,負數的反碼是在其原碼的基礎上,符號位不變,其餘各位取反),這里不分正負數,直接每個位都取反!
上面加粗的那句是跟我們一般的加法規則不太一樣的地方:最高位有進位,則向最低位進1。確實有些疑惑,為什麼要這樣做呢?仔細分析一下(為了方便說明,以 4bit二進制反碼求和舉例),上面的這種操作,使得在發生加法進位溢出時,溢出的值並不是10000,而是1111。也即是當相加結果滿1111時溢出,這樣也可以說明為什麼0000和1111都表示0了(你同樣可以發現,任何數與這兩個數做二進制反碼求和運算結果都是原數,這恰好符合數0的加法意義)。
下面再舉例兩種二進制反碼求和的運算:
原碼加法運算 反碼加法運算
3(0011)+ 5(0101)= 8(1000) 3(1100)+ 5(1010)= 8(0111)
8(1000)+ 9(1001)= 1(0001) 8(0111)+ 9(0110)= 2(1101)
從上面兩個例子可以看出,當加法未發生溢出時,原碼與反碼加法運算結果一樣;當有溢出時,結果就不一樣了,原碼是滿10000溢出,而反碼是滿1111溢 出,所以相差正好是.
1。舉例只是為了形象地觀察二進制反碼求和的運算規則,至於為什麼要定義這樣的規則以及該運算規則還存在其它什麼特性,可能就需要涉及 代數理論的東西的了(嗚嗚~~數學理論沒學好啊,只能從表面上分析分析)。
另外關於二進制反碼求和運算需要說明的一點是,先取反後相加與先相加後取反,得到的結果是一樣的!(事實上我們的編程演算法里,幾乎都是先相加後取反。)
2. 校驗和演算法的實現
講了什麼是二進制反碼求和,那麼校驗和的演算法實現就簡單多了。廢話少說,直接上代碼:
[cpp] view plain
//計算校驗和
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必須是32bit的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. 為什麼使用二進制反碼求和呢?
好了,最後一個問題,為什麼要使用二進制反碼來計算校驗和呢,而不是直接使用原碼或者補碼?
這個問題我想了很久,由於水平有限實在弄不明白,於是在網路上一陣狂搜,什麼都沒有(不知道是網路不給力,還是大家都不關注這個問題呢?)。果斷換google,敲了3個關鍵詞:why checksum tcp,嘿嘿 結果第二篇就是我想要的文章了!!!
先把鏈接給大家吧:http://www.netfor2.com/checksum.html
這篇文章主要介紹二進制反碼求和(the 1's complement sum)與補碼求和(the 2's complement sum)的區別,另外還說明了在TCP/IP校驗和中使用反碼求和的優點。
It may look awkword to use a 1's complement addition on 2's complement machines. This method however has its own benefits.
Probably the most important is that it is endian independent. Little Endian computers store hex numbers with the LSB last (Intel processors for example). Big Endian computers put the LSB first (IBM mainframes for example). When carry is added to the LSB to form the 1's complement sum (see the example) it doesn't matter if we add 03 + 01 or 01 + 03. The result is the same.
Other benefits include the easiness of checking the transmission and the checksum calculation plus a variety of ways to speed up the calculation by updating only IP fields that have changed.
上面是原文的一部分,說明在TCP/IP校驗和中使用反碼求和的一些優點:
a. 不依賴系統是大端還是小端。 即無論你是發送方計算或者接收方檢查校驗和時,都不需要調用htons 或者 ntohs,直接通過上面第2節的演算法就可以得到正確的結果。這個問題你可以自己舉個例子,用反碼求和時,交換16位數的位元組順序,得到的結果相同,只是位元組順序相應地也交換了;而如果使用原碼或者補碼求和,得到的結果可能就不相同!
b. 計算和驗證校驗和比較簡單,快速。說 實話,這個沒怎麼看明白,感覺在校驗和計算方面,原碼或者補碼求和反而更簡單一些(從C語言角度),在校驗和驗證上面,通過一樣的演算法判斷結果是否為全 0,確實要方便一些,所以可能從綜合考慮確實反碼求和要簡便一些。另外,IP報文在傳輸過程中,路由器經常只修改TTL欄位(減1),此時路由器轉發該報 文時可以直接增加它的校驗和,而不需要對IP整個首部進行重新計算。當然,可能從匯編語言的角度看,反碼求和還有很多高效的地方,這里就不在深入追究 了~~~
❷ 怎麼計算UDP檢驗和(最好是有詳細例子分析)
去查書吧
謝希仁《計算機網路>上有
你先看ip檢驗和那節,再看udp那節
❸ IP/UDP/TCP/ICMP數據報協議的校驗和的區別和計算
1、把校驗和欄位置為0;
2、對IP頭部中的每16bit進行二進制求和;
3、如果和的高16bit不為0,則將和的高16bit和低16bit反復相加,直到和的高16bit為0,從而獲得一個16bit的值;
4、將該16bit的值取反,存入校驗和欄位。
❹ 用java實現UDP校驗和計算
public static void main(String[] arg) {
String str = "hello";
System.out.println(toByte(str));
// 得到結果:byte[] sbytes = { 0X68, 0X65, 0X6c, 0X6c, 0X6f };
}
private static String toByte(String str) {
byte[] bytes = str.getBytes();
StringBuffer sb = new StringBuffer();
sb.append("byte[] sbytes = { ");
for (int i = 0; i < bytes.length; i++) {
sb.append(String.format("0X%s", Integer.toHexString(bytes[i])));
if (i < bytes.length - 1) {
sb.append(", ");
}
}
sb.append(" };").append("\r\n");
return sb.toString();
}
❺ UDP計算校驗和為什麼要用1的補碼
UDP的校驗和包括UDP首部和數據,方法是計算16位的二進制和,首先將校驗
和欄位(16位)置0,將每個16位的反碼相加,若是奇數位元組即最後未到16位元組,
則以0補充,結果存在校驗和欄位中,因接收端包含了之前的校驗和,若傳輸
中沒有任何差錯,則接收端計算的校驗和該為全1,否則有錯。
❻ UDP偽首部的作用和怎麼計算UDP的檢驗和這個檢驗和是否涵蓋偽首部內容還是只是UDP數據包的內容
首先,要時刻謹記一個「偽」字,既然是「偽」首部,也就是假的,不僅是「假」首部,而且「假」到連地址空間都沒有。也就是說偽首部是不佔地址空間的,在實際傳輸中不存在這樣的欄位。只是在使用的時候把它拿出來一下。
其次,設置了偽首部,為了計算檢驗和!書中原話「其目的是讓UDP兩次檢查數據是否已經正確到達目的地」,具體是那兩次呢?我們注意偽首部欄位:32位源IP地址、32位目的IP地址、8位協議、16位UDP長度。由此可知,第一次,通過偽首部的IP地址檢驗,UDP可以確認該數據報是不是發送給本機IP地址的;第二,通過偽首部的協議欄位檢驗,UDP可以確認IP有沒有把不應該傳給UDP而應該傳給別的高層的數據報傳給了UDP。從這一點上,偽首部的作用其實很大。
❼ 如何計算UDP/TCP檢驗和checksum
如何計算UDP/TCP檢驗和checksum 一、下面的圖是一個UDP的檢驗和所需要用到的所有信息,包括三個部分: 1.UDP偽首部 2.UDP首部 3.UDP的數據部分(切記不要遺漏該部分,否則就~吐血了~) 首先解釋下偽首部的概念,偽首部包含IP首部一些欄位。其目的是讓UDP兩次檢查數據是否已經正確到達目的地,只是單純為了做校驗用的。 還有一個概念十分重要,那就是16位UDP總長度,請注意該長度不是報文的總長度,而只是UDP(包括UDP頭和數據部分)的總長度(之前就是因為這個概念沒弄清楚,走了不少彎路,吐血~~)。 二、計算檢驗和(checksum)的過程很關鍵,主要分為以下幾個步驟: 1.把偽首部添加到UDP上; 2.計算初始時是需要將檢驗和欄位添零的; 3.把所有位劃分為16位(2位元組)的字 4.把所有16位的字相加,如果遇到進位,則將高於16位元組的進位部分的值加到最低位上,舉例,0xBB5E+0xFCED=0x1 B84B,則將1放到最低位,得到結果是0xB84C 5.將所有字相加得到的結果應該為一個16位的數,將該數取反則可以得到檢驗和checksum。 三、事實勝於雄辯,還是舉個例子來分析一下吧,該例子計算的是一個TCP的檢驗和(和UDP的演算法一致) TCP計算檢驗和的報文結構如下所示: 抓包工具抓了一個TCP 的syn報文做研究,呵呵,下面就是整個報文: 1.首先將檢驗和部分添零; 2.然後將TCP偽首部部分,TCP首部部分,數據部分都劃分成16位的一個個16進制數; 3.將這些數逐個相加,記得溢出的部分加到最低位上,這是循環加法: 0xc0a8+ 0x0166+……+0x0402=0x9b49 4.最後將得到的結果取反,則可以得到檢驗和位0x64B6 按照上述步驟進行計算就可以得到檢驗和為0x64B6,大家也可以試試看 IP數據報只檢驗IP數據報的首部,但UDP檢驗的是把首部和數據部分一起都檢驗。
❽ 校驗和怎麼計算
檢驗和(checksum),在數據處理和數據通信領域中,用於校驗目的地一組數據項的和。它通常是以十六進制為數製表示的形式。如果校驗和的數值超過十六進制的FF,也就是255. 就要求其補碼作為校驗和。通常用來在通信中,尤其是遠距離通信中保證數據的完整性和准確性。
這些數據項可以是數字或在計算檢驗的過程中看作數字的其它字元串。校驗和(checksum)是指傳輸位數的累加,當傳輸結束時,接收者可以根據這個數值判斷是否接到了所有的數據。如果數值匹配,那麼說明傳送已經完成。TCP和UDP傳輸層都提供了一個校驗和與驗證總數是否匹配的服務功能。[1]
它通常是以十六進制為數製表示的形式
發送方生成檢驗和
1.將發送的進行檢驗和運算的數據分成若干個16位的位串,每個位串看成一個二進制數,這里並不管字元串代表什麼,是整數、浮點數還是點陣圖都無所謂。
2.將IP、UDP或TCP的PDU首部中的檢驗和欄位置為0,該欄位也參與檢驗和運算。
3.對這些16位的二進制數進行1的補碼和(one'scomplementsum)運算,累加的結果再取反碼即生成了檢驗碼。將檢驗碼放入檢驗和欄位中。
其中1的補碼和運算,即帶循環進位(end round carry)的加法,最高位有進位應循環進到最低位。反碼即二進制各位取反,如0111的反碼為1000。
接收方校驗檢驗和
1.接收方將接收的數據(包括檢驗和欄位)按發送方的同樣的方法進行1的補碼和運算,累加的結果再取反碼。
2.校驗,如果上步的結果為0,表示傳輸正確;否則,說明傳輸有差錯。
❾ IP,UDP,TCP校驗和有什麼區別
UDP計算校驗和的方法和計算IP數據報首部校驗和的方法相似。 但不同的是:IP數據報的校驗和只檢驗IP數據報的首部,但UDP的校驗和是將首部和數據部分一起都檢驗。 在發送端,首先是將全零放入檢驗和欄位。再將偽首部以及UDP用戶數據報看成是由許多16bit的字串接起來。 若UDP用戶數據報的數據部分不是偶數個位元組,則要填入一個全零位元組(即:最後一個基數位元組應是16位數的高位元組而低位元組填0)。 然後按二進制反碼計算出這些16bit字的和(兩個數進行二進制反碼求和的運算的規則是:從低位到高位逐列進行計算。 0和0相加是0,0和1相加是1,1和1相加是0但要產生一個進位1,加到下一列。若最高位相加後產生進位,則最後得到的結果要加1)。 將此和的二進制反碼寫入校驗和欄位後,發送此UDP用戶數據報。 在接收端,將收到的UDP用戶數據報連同偽首部(以及可能的填充全零位元組)一起,按二進制反碼求這些16bit字的和。 當無差錯時其結果應全為1。否則就表明有差錯出現, 接收端就應將此UDP用戶數據報丟棄(也可以上交給應用層,但附上出現了差錯的警告)。
TCP 的校驗和計算方法同UDP一樣,同樣要加上一個偽頭部,區別是偽頭部的協議碼是0x06,長度是整個TCP報文的長度(包含TCP頭部)。
ICMP的校驗和
ICMP校驗和的計算方法一樣,只不過只是對ICMP包整個進行校驗和,沒有偽頭部,也不包括IP包頭部。
❿ java UDP檢驗和計算
byte ->char 強制轉換,,, 直接得到ascii了。 2個字元,得到的數據開始是byte[],隨便加減了。