(2019年2月19日注:這篇文章原先發在自己github那邊的博客,時間是2016年7月12日)
周四要給工作室的小朋友們繼續培訓計算機網絡,要講的內容是傳輸層,於是今天就在准備相應的材料,重新看回謝希仁老師的課本過程中又加深了一點理解,然后看到了當時碰到的第一個難點,UDP協議的校驗和的計算。
其實本質上來說這個計算原理還是不難的,就是一個二進制反碼求和運算,具體來說就是:$$0+0=0$$ $$1+0=0+1=1$$ $$1+1=10$$
其中10中的1加到了下一列去,如果是最高列的1+1,那么得到的10留下0,1移到最低列,與最低位再做一次二進制加法即可。
在謝老師的這本書里,講到的是一個15字節的UDP數據在發送方怎么進行數據的檢驗,然后列出了一個二進制的豎式並給出一個結果,然而並沒有講述是怎么計算出來的。經過我不斷的努力,終於把二進制計算的過程整個寫出來了。之前在數計院上課的時候,老師講過一個較為之簡單的十六進制計算法,對比之下確實是簡單很多。好了,先上圖。
謝老師在課本里面給出的題目是這樣子的。
二進制版 1001 1001 0001 0011 //偽首部源IP地址前16位 0000 1000 0110 1000 //偽首部源IP地址后16位 1010 1011 0000 0011 //偽首部目的IP地址前16位 0000 1110 0000 1011 //偽首部目的IP地址后16位 0000 0000 0001 0001 //偽首部UDP協議字段代表號17,前面8位是填充0 0000 0000 0000 1111 //偽首部UDP長度字段 0000 0100 0011 1111 //UDP頭部源IP地址對應的進程端口號 0000 0000 0000 1101 //UDP頭部目的IP地址對應的進程端口號 0000 0000 0000 1111 //UDP頭部UDP長度字段 0000 0000 0000 0000 //UDP頭部UDP檢驗和 0101 0100 0100 0101 //數據字段 0101 0011 0101 0100 //數據字段 0100 1001 0100 1110 //數據字段 0100 0111 0000 0000 //數據字段+填充0字段 十六進制版 9913 //偽首部源IP地址前16位 0868 //偽首部源IP地址后16位 AB03 //偽首部目的IP地址前16位 0E0B //偽首部目的IP地址后16位 0011 //偽首部UDP協議字段代表號17,前面8位是填充0 000F //偽首部UDP長度字段 043F //UDP頭部源IP地址對應的進程端口號 000D //UDP頭部目的IP地址對應的進程端口號 000F //UDP頭部UDP長度字段 0000 //UDP頭部UDP檢驗和 5445 //數據字段 5354 //數據字段 494E //數據字段 4700 //數據字段+填充0字段
在二進制版中,是不可以直接從右邊第一列開始做豎式相加的,不要說十進制的豎式相加,二進制的豎式相加都做不到。
正確的做法是:
(1) 讓第一行和第二行做二進制反碼運算。
根據上述的規則,當碰到1+1=10時,在左鄰側一列下面寫個小1(類似以前做十進制進位加法),然后側列進行二進制反碼運算得出一個數,如果沒有進位,就繼續與剛才的進位做二進制反碼運算,如果有進位,則先把進位的小1寫在相鄰高側列的下方,取個位來與其相加。有進位的只有1+1=10的情況,0不論加什么進位都不會有進位,而如果第一次計算沒有進位時,只有產生1的情況下才會有進位,總而言之,對於每一列,都只會有至多一次的進位,所以不用擔心進位會跨列的問題。這樣子做要注意的就是不要寫錯數字了,比如我自己在寫這張紙之前已經打過兩次草稿了,然而還是會寫錯。
對於高位有1的情況,就是把1挪到最低位,再做一次二進制反碼計算,本質來說就是取補碼。
(2) 將第一行和第二行的結果與第三行做二進制反碼計算,以此類推。
(3) 運算結果取反,得到校驗和。
在十六進制版中,運算量會大大減小,主要的計算步驟如下:
(1) 從右邊第一列開始,按照十進制來計算第一列的值。
在這里第一列算出來是107,寫成8位二進制就是01101011。
(2) 根據算出來的結果分成兩部分,左邊的4位化成十進制,作為下一列進位時加的數,右邊4位化成16進制,作為第一列的結果。
這里就是610B16,圖片誤算成D,6作為下一列運算時要加上的對象,B作為第一列的結果。
(3) 十進制計算第二列的結果,加上第一列得到的進位得到第二列的一個十進制數字,化為二進制,根據第二步來進行判斷,依次類推。
在這里第二列算到的是24,加上6就是30,化為8位二進制就是00011110,也就是1E,第二列的結果為1,第三列的十進制進位為1。接着可以算到第三列的結果為6,十進制進位為4。
(4) 最高位算出最后的十進制結果后,化為二進制時,右邊4位作為最終結果,左邊4位移入下一列,用上一步得到的結果96EB,加上0010,得到最后結果,這里圖片的最后一步寫錯了,不應該舍棄。
最后能得到結果為96ED。
(5) 結果取反,得到校驗碼。
校驗碼為6912。
好了這次先針對這個特定的問題提出了解決方案,有時間要好好整理下關於計算機的原碼、反碼和補碼的知識。