1. 程式人生 > >分組重傳機制---可靠資料傳輸原理。

分組重傳機制---可靠資料傳輸原理。

不知道從哪天開始,一禪也陷入了程式設計這條道路.....

小白:你知道嗎?資料在傳輸的時候是分割成一小塊一小塊傳輸的,我們把這一小塊的資料稱之為一個分組。我們在傳輸這塊分組的時候,主要面臨兩個問題。

1、這個分組在傳輸的過程中,由於在通道傳輸過程中,收到干擾,導致這個分組到達目的地之後出現了差錯,例如分組裡面的二進位制位1變成了0,0變成了1。

2、分組還沒傳輸到目的地,就丟失了,我們也把這種情況稱之為丟包

接下來我們先來談談第一種情況吧,即分組傳到目的地之後出現了差錯。

這裡我們先假設計算機A給計算機B傳送分組資料

一禪:如果沒有差錯的話,計算機B就給計算機A傳送一個ACK

分組,告訴對方,資料正確無誤。如果出現差錯的話,就給對方傳送一個NAK分組,告訴對方,分組資料出現了差錯。

當計算機A收到接受方的反饋之後,如果收到的是ACK分組,那麼就繼續傳送下一個分組資料。如果收到的是NAK分組,那麼就重新傳輸這個分組。

小白:這時就會出現了混亂,就相當於兩個人A,B在對話。

A : 傳輸給你一個分組

B :你發的是啥,可以重發一次嗎?

A :你發的又是啥?可以重發一次嗎?

B :你發的又是啥?可以重發一次嗎

......

進去無限混亂之中

小白:法子倒是不錯,不過如果分組出現大量差錯,會讓校驗碼變的很難設計的,而且校驗碼屬於與正文內容無關的資料,佔了太多位元位的話,會降低傳輸效率。還有其他法子嗎?

小白:我們可以給每個分組新增一個序號啊,這樣就可以知道是重傳的分組還是新的分組了。

如果B收到的分組沒出差錯,這時又收到一個序號相同的分組,這時B就知道這個分組是屬於重傳的分組了,這時B就把這個重傳的分組丟棄。

情況二:分組丟失時的問題處理

一禪:哈哈,我知道怎麼解決,可以採取和分組差錯類似的方法,如果A遲遲沒有收到B的反饋,A就可以認為這個分組丟失了,重新發送。

所以我們每次傳送分組的時候,需要給該分組設定一個定時器

小白:腦子轉的挺快啊。不過你知道嗎?我們上面談的那些,都是A傳送一個分組,收到B的反饋之後,再發送下一個分組。你不覺得這種方法很浪費通道的資源嗎?

這裡先說明一下,如果同時傳送多個分組時,最需要處理的問題就是接受方收到分組時,並非按照順序收到分組的,有可能序號小的分組先達到,這時就會出現了亂序。

回退N步協議(GBN)

在回退N步法中允許傳送多個分組而不需要等待確認,但它也受限於在流水線中未確認的分組數不能超過某個最大允許數N。如下圖,我們將基序號定義為最早的未確認分組的序號,將下一個序號(nextseqnum)定義為最小的未使用序號(即下一個待發送分組)。

此時我們可以將序號分成4段。在[0, base-1]段內的序號對應已傳送並且已經確認的分組序號,[base,nextseqnum]段內對應已經發送但未確認的分組序號,[nextseqnum, base+N-1]段內表示即將要被髮送的分組序號。而那些大於base+N的序號目前還不能使用,直到當前流水線中未被確認的分組得到確認,視窗整體向右移動之後,才能夠被使用。

所以,我們常把N稱之為視窗長度,由於視窗在序號範圍內移動,也被GBN協議稱之為滑動視窗協議

對於GBN協議,計算機A(傳送方)需要響應以下兩個事件:

1、收到一個ACK:在GBN協議中,對序號為n的分組的確認採取累計確認的方式。也就是說,當A收到序號為n的分組時,表明分組n以及n之前的分組已經被B正確接受了。

2、超時事件: 當久久沒有收到ACK時,A就認為它傳送的分組已經丟失了,這時A會重傳所有已傳送但還未被確認的分組。這個時候需要注意的是,並不是為每個分組設定一個定時器,而是在序號[base,nextseqnum-1]中,設定一個定時器,當base傳送的那一刻,就開始計時,當收到一個ACK時,則重新整理重新開始計時。

計算機B(接收方)則需要處理一下事件:

如果一個序號為n的分組被正確收到,並且按序(所謂按序就是指n-1的分組也已經收到了),則B為分組n傳送一個ACK,否則,丟棄該分組,並且為最近按序接收的分組重新發送ACK。

接收方的這種處理方式,意味著如果n被正確交付,則意味著比n小的所有分組也被正確交付了。

小白:你這個想法其實也是挺不錯的,不過如果分組n-1丟失了,那麼按照GBN的重傳規則,這時n-1和n都會被重傳,這時之前快取的n就沒啥用了。而且,我們如果把n丟棄了,那麼我們就不需要快取任何失序的分組了,這樣可以讓我們的設計更加簡單哦。

選擇重傳(SR)

回退N步協議的缺點也是很明顯的,單個分組的差錯能夠引起GBN重傳大量的分組,而且許多分組根本就沒有必要重傳。例如我們傳送的序號為0-100,萬一序號為1的分組出現了某些差錯,這會導致1-100的分組會被重傳,想想這是多麼恐怖的事情啊。

因此,出現了選擇重傳這種協議。所謂“選擇”,也就是有選擇著去重傳。

不過選擇重傳和回退N步是很相似的,只是在選擇重傳中,接收方收到失序的分組時,會把它快取起來,直到拼湊到分組按序,才把分組傳輸給上一層。而傳送方會為每個分組設定一個定時器,這樣,只需要重傳那些沒有被接收方正確接收的分組就可以了。

我來個例子吧。

假設視窗長度N=6,這時A向B傳送分組1-5。

當A收到序號為3的ACK,則狀態如下:

注意,這個時候雖然序號3被確認接收了,但視窗並不能向右移動一格。

接下來受到序號為1的ACK,則:

這個時候窗口才可以向右移動一格。注意,黃色的那些序號是可以繼續傳送分組的,只是我沒有繼續填充發送而已。

接著收到序號為2的分組。

這個時候視窗向右移動了兩個格。

接著繼續這樣接收下去,如果還有分組沒傳送的,就從nextseqnum開始填充發送...

如果某個分組超時了,就重新傳輸這個分組。

對於接收方B的視窗來說也差不多也一樣,在此不展開。接收方對於失序的分組快取起來,直到所有丟失的分組全部被收到為止,再把這批分組按序交付給上一層。

我在書上截了張完整的例子圖:

這樣,兩個完全陌生的計算機就可以就行可靠資料傳輸了。這也是可靠資料傳輸的原理

最後一點感想

總感覺這篇文章講的好一般,感覺有點小囉嗦或者.....也不知道怎麼說,本來我是想寫成那種一點一點引匯出知識點的,不過在回退N步選擇重傳中,有點不知道怎麼引導。不過我會爭取在後面的文章講的更加通俗易懂。

說實話,這篇文章其實算是比較簡單的幾個知識點,不過我還是寫了好久,加上自己畫圖之列的就更加了,哈哈。主要是一直不知道怎麼下手。不過就算花時間,我也會盡最大努力去寫。再次感謝讀者們的支援,在之後的文章裡,應該會資料結構與演算法和計算機網路穿插講。

希望通過這種漫文的方式,能夠讓你更加輕鬆的讀懂某些知識。

更多原創漫畫文章,可以關注我的公眾號:苦逼的碼農(ID:di201805),文章會首發於我的公眾號

本公眾號(苦逼的碼農)專注於寫【Java】、【計算機網路】、【資料結構與演算法】,力求通俗易懂,期待你加入交流。