滑動窗口協議

仍然考慮鏈路的延遲與帶寬的乘積爲8 K B,幀尺寸爲1 K B的情形。讓發送方在收到第一幀的A C K的同時準備發送第九幀。允許我們這樣做的算法稱爲滑動窗口( sliding window),時間線如圖2 - 2 1所示。

1. 滑動窗口算法

滑動窗口算法工作過程如下。首先,發送方爲每1幀賦一個序號(sequence number),記作S e q N u m。現在,讓我們忽略S e q N u m是由有限大小的頭部字段實現的事實,而假設它能無限增大。發送方維護3個變量:發送窗口大小(send window size),記作S W S,給出發送方能夠發 

送但未確認的幀數的上界; L A R表示最近收到的確認幀( last acknowledgement re c e i v e d)的序號;L F S表示最近發送的幀(last frame sent)的序號,發送方還維持如下的不變式:
LAR-LFR≤RWS 

 
當一個確認到達時,發送方向右移動L A R,從而允許發送方發送另一幀。同時,發送方爲所發的每個幀設置一個定時器,如果定時器在A C K到達之前超時,則重發此幀。注意:發送方必須存儲最多S W S個幀,因爲在它們得到確認之前必須準備重發。
接收方維護下面3個變量:接收窗口大小(receive window size),記爲RW S,給出接收方所能接收的無序幀數目的上界; L A F表示可接收幀(l a rgest acceptable frame)的序號;L F R表示最近收到的幀(last frame re c e i v e d)的序號。接收方也維持如下不變式:
LFS-LAR≤SWS 

 
當一個具有順序號S e q N u m的幀到達時,接收方採取如下行動:如果S e q N u m≤L F R或S e q N u m > L A F,那麼幀不在接收窗口內,於是被丟棄;如果L F R<Se q N u m≤L A F,那麼幀在接收窗口內,於是被接收。現在接收方需要決定是否發送一個A C K。設S e q N u m To A C K表示未被確認幀的最大序號,則序號小於或等於S e q N u m To A c k的幀都已收到。即使已經收到更高序號的分組,接收方仍確認S e q N u m To A c k的接收。這種確認被稱爲是累積的(c u m u l a t i v e)。然後它設置L F R = S e q N u m To A c k,並調整L A F = L F R + RW S。例如,假設L F R= 5(即,上次接收方發送的A C K是爲了確認順序號5的),並且RWS = 4。這意味着L A F = 9。如果幀7和8到達,則存儲它們,因爲它們在接收窗口內。然而並不需要發送A C K,因爲幀6還沒有到達。幀7和8被稱爲是錯序到達的。(從技術上講,接收方可以在幀7和8到達時重發幀5的A C K。)如果幀6當時到達了(或許它在第一次丟失後又重發從而晚到,或許它只是被延遲了),接收方確認幀8,L F R置爲8,L A F置爲1 2。如果實際上幀6丟失了,則出現發送方超時,重發幀6。我們看到,當發生超時時,傳輸數據量減少,這是因爲發送方在幀6確認之前不能向前移動窗口。這意味着分組丟失時,此方案將不再保證管道滿載。注意:分組丟失時間越長,這個問題越嚴重。
注意,在這個例子中,接收方可以在幀7剛一到達時就爲幀6發送一個認幀N A K(negative acknowl edgment)。然而,由於發送方的超時機制足以發現這種情況,發送N A K反而爲發送方增加了複雜性,因此不必這樣做。正如我們已提到的,當幀7和8到達時爲幀5發送一個額外的A C K是合理的;在某些情況下,發送方可以使用重複的A C K作爲一個幀丟失的線索。這兩種方法都允許早期的分組丟失檢測,有助於改進性能。
關於這個方案的另一個變種是使用選擇確認(selective acknowledgements)。即,接收方能夠準確地確認那些已收到的幀,而不只是確認按順序收到最高序號的幀。因此,在上例中,接收方能夠確認幀7、8的接收。如果給發送方更多的信息,就能使其較容易地保持管道滿載,但增加了實現的複雜性。
發送窗口大小是根據一段給定時間內鏈路上有多少待確認的幀來選擇的;對於一個給定的延遲與帶寬的乘積,S W S是容易計算的。另一方面,接收方可以將RW S設置爲任何想要的值。通常的兩種設置是:RW S= 1,表示接收方不存儲任何錯序到達的幀; RW S=S W S,表示接收方能夠緩存發送方傳輸的任何幀。由於錯序到達的幀的數目不可能超過S W S個,所以設置RWS >S W S沒有意義。

2. 有限順序號和滑動窗口

現在我們再來討論算法中做過的一個簡化,即假設序號是可以無限增大的。當然,實際上是在一個有限的頭部字段中說明一個幀的序號。例如,一個3比特字段意味着有8個可用序號0 ~ 7。因此序號必須可重用,或者說序號能迴繞。這就帶來了一個問題:要能夠區別同一序號的不同次發送實例,這意味着可用序號的數目必須大於所允許的待確認幀的數目。例如,停止等待算法允許一次有1個待確認幀,並有2個不同的序號。
假設序號空間中的序號數比待確認的幀數大1,即S W S ≤ M A a x S e q N u m -1 ,其中M a x Seq N u m 是可用序號數。這就夠了嗎?答案取決於RW S 。如果RW S = 1,那麼MaxSeqNum≥SWS+1是足夠了。如果RW S等於S W S,那麼有一個只比發送窗口尺寸大1的M a x S e q N u m是不夠的。爲看清這一點,考慮有8個序號0 ~ 7的情況,並且S W S = RW S = 7。假設發送方傳輸幀0 ~ 6,並且接收方成功接收,但A C K丟失。接收方現在希望接收幀7,0 ~ 5,但發送方超時,然後發送幀0 ~ 6。不幸的是,接收方期待的是第二次的幀0 ~ 5,得到的卻是第一次的幀0 ~ 5。這正是我們想避免的情況。
結果是,當RW S = S W S時,發送窗口的大小不能大於可用序號數的一半,或更準確地說,SWS<(Maxseqnum+1)/2直觀地,這說明滑動窗口協議是在序號空間的兩半之間變換,就像停止等待協議的序號是在0和1之間變換一樣。唯一的區別是,它在序號空間的兩半之間連續滑動而不是離散的變換。
注意,這條規則是特別針對RW S = S W S的。我們把確定適用於RW S和S W S的任意值的更一般的規則留做一個練習。還要注意,窗口的大小和序號空間之間的關係依賴於一個很明顯以至於容易被忽略的假設,即幀在傳輸中不重新排序。這在直連的點到點鏈路上不能發生,因爲在傳輸過程中一個幀不可能趕上另一個幀。然而,我們將在第5章看到用在一個不同環境中的滑動窗口算法,並且需要設計另一條規則。
 
3. 滑動窗口的實現

下面的例程說明我們如何實現滑動窗口算法的發送和接收的兩個方面。該例程取自一個正在使用的協議,稱爲滑動窗口協議S W P(Sliding Window Pro t o c o l)。爲了不涉及協議圖中的鄰近協議,我們用H L P(高層協議)表示S W P上層的協議,用L I N K(鏈路層協議)表示S W P下層的協議。我們先定義一對數據結構。首先,幀頭部非常簡單:它包含一個序號( S e q N u m)和一個確認號( A c k N u m)。它還包含一個標誌( F l a g s)字段,表明幀是一個A C K幀還是攜帶數據的幀。

其次,滑動窗口算法的狀態有如下結構。對於協議發送方,該狀態包括如上所述的變量L A R和L F S,以及一個存放已發出但尚未確認的幀的隊列( s e n d Q)。發送方狀態還包含一個計數信號量( counting semaphore),稱爲s e n d Wi n d o w N o t F u l l。下面我們將會看到如何使用它,但一般來說,信號量是一個支持s e m Wa i t和s e m S i g n a l操作的同步原語。每次調用S e m S i g n a l,信號量加1,每次調用S e m Wa i t,信號量減1。如果信號量減小,導致它的值小於0,那麼調用進程阻塞(掛起)。一旦執行了足夠的s e m S i g n a l操作而使信號量的值增大到大於0,在調用s e m Wa i t的過程中阻塞的進程就允許被恢復。
對於協議的接收方,如前所述,該狀態包含變量L F R ,加上一個存放已收到的錯序幀的隊列(r e c v Q)。最後,雖然未顯示,發送方和接收方的滑動窗口的大小分別由常量S W S和RW S表示。

S W P的發送方是由s e n d S W P過程實現的。這個例程很簡單。首先, s e m Wa i t使這個進程在一個信號量上阻塞,直到它可以發另一幀。一旦允許繼續, s e n d S W P設置幀頭部中的順序號,將此幀的拷貝存儲在發送隊列( s e n d Q)中,調度一個超時事件以便處理幀未被確認的情況,並將幀發給低層協議。
值得注意的一個細節是剛好在調用m s g A d d H d r之前調用s t o r e _ s w p _ h d r。該例程將存有S W P頭部的C語言結構( s t a t e - > h d r)轉化爲能夠安全放在消息前面的字節串( h b u f)。該例程(未給出)必須將頭部中的每一個整數字段轉化爲網絡字節順序,並且去掉編譯程序加入C語言結構中的任意填充。7 . 1節將詳細討論字節順序的問題,但現在,假設該例程將多字整數中最高有效位放在最高地址字節就足夠了。
這個例程的另一個複雜性是使用s e m Wa i t 和s e n dW i n d o w N o t F u l l 信號量。S e n dWi n d o w N o t F u l l被初始化爲發送方滑動窗口的大小S W S(未給出這一初始化)。發送方每傳輸一幀, s e m Wa i t操作將這個數減1,如果減小到0,則阻塞發送方進程。每收到一個A C K,在d e l i v e r S W P中調用s e m S i g n a l操作(見下面)將此數加1,從而激活正在等待的發送方進程。

在繼續介紹S W P的接收方之前,需要調整一個看上去不一致的地方。一方面,我們說過,高層協議通過調用s e n d操作來請求低層協議的服務,所以我們就希望通過S W P發送消息的協議能夠調用s e n d(S W P, p a c k e t)。另一方面,用來實現S W P的發送操作的過程叫做s e n d S W P,並且它的第一個參數是一個狀態變量( S w p S t a t e)。結果怎樣呢?答案是,操作系統提供了粘結代碼將對s e n d的一般調用轉化爲對s e n d S W P的特定協議調用的粘結代碼。這個粘結代碼將s e n d的第一個參數(協議變量S W P)映射爲一個指向s e n d S W P的函數指針和一個指向S W P工作時所需的協議狀態的指針。我們之所以通過一般函數調用使高層協議間接調用特定協議函數,是因爲我們想限制高層協議中對低層協議編碼的信息量。這使得將來能夠比較容易地改變協議圖的配置。現在來看d e l i v e r操作的S W P的特定協議實現,它在過程d e l i v e r S W P中實現。這個例程實際上處理兩種不同類型的輸入消息:本結點已發出幀的A C K和到達這個結點的數據幀。在某種意義上,這個例程的ACK部分是與send SWP中所給算法的發送方相對應的。通過檢驗頭部的F l a g s字段可以確定輸入的消息是ACK還是一個數據幀。注意,這種特殊的實現不支持數據幀中捎帶A C K。當輸入幀是一個ACK時,delive rSWP僅僅在發送隊列(send Q)中找到與此ACK相應的位置(slot),取消超時事件,並且釋放保存在那一位置的幀。由於A C K可能是累積的,所以這項工作實際上是在一個循環中進行的。對於這種情況值得注意的另一個問題是子例程swp In Wind o w的調用。這個子例程在下面給出,它確保被確認幀的序號是在發送方當前希望收到的A C K的範圍之內。
當輸入幀包含數據時, d e l i v e r S W P首先調用m s g S t r i p H d r和l o a d _ s w p _ h d r以便從幀中提取頭部。例程l o a d _ s w p _ h d r對應着前面討論的s t o r e _ s w p _ h d r,它將一個字節串轉化爲容納S W P頭部的C語言數據結構。然後d e l i v e r S W P調用s w p I n Wi n d o w以確保幀序號在期望的序號範圍內。如果是這樣,例程在已收到的連續的幀的集合上循環,並通過調用d e l i v e r H L P例程將它們傳給上層協議。它也要向發送方發送累積的A C K,但卻是通過在接收隊列上循環來實現的(它沒有使用本節前面給出的s e q N u m To A c k變量)。

 

最後,s w p I n Window 是一個簡單的子例程,它檢查一個給定的序號是否落在某個最大和最小順序號之間。

 
4. 幀順序和流量控制

滑動窗口協議可能是計算機網絡中最著名的算法。然而,關於該算法易產生混淆的是,它可以有三個不同的功能,第一個功能是本節的重點,即在不可靠鏈路上可靠地傳輸幀。(一般來說,該算法被用於在一個不可靠的網絡上可靠地傳輸消息。)這是該算法的核心功能。
滑動窗口算法的第二個功能是用於保持幀的傳輸順序。這在接收方比較容易實現,因爲每個幀有一個序號,接收方要保證已經向上層協議傳遞了所有序號比當前幀小的幀,才向上傳送該當前幀。即,接收方緩存了(即沒有傳送)錯序的幀。本節描述的滑動窗口算法確實保持了幀的順序,儘管我們可以想象一個變異,即接收方沒有等待更早傳送的幀都到達就將幀傳給下一個協議。我們可以提出的一個問題是:我們是否確實需要滑動窗口協議來保持幀的順序,或者,這樣的功能在鏈路層是否是不必要的。不幸的是,我們還沒有看到足夠多的網絡體系結構來回答這個問題我們首先需要理解的是,點到點鏈路序列如何由交換機連接而形成一條端到端的路徑。
滑動窗口算法的第三個功能是,它有時支持流量控制(f l o w c o n t ro l),它是一種接收方能夠控制發送方使其降低速度的反饋機制。這種機制用於抑制發送方發送速度過快,即抑制傳輸比接收方所能處理的更多的數據。這通常通過擴展滑動窗口協議完成,使接收方不僅確認收到的幀,而且通知發送方它還可接收多少幀。可接收的幀數對應着接收方空閒的緩衝區數。在按序傳遞的情況下,在將流量控制併入滑動窗口協議之前,我們應該確信流量控制在鏈路層是必要的。
尚未討論的一個重要概念是系統設計原理,我們稱其爲相關性分離(separation of concerns)。即,你必須小心區別有時交織在一種機制中的不同功能,並且你必須確定每一個功能是必要的,而且是被最有效的方式支持的。在這種特定的情況下,可靠傳輸、按序傳輸和流量控制有時組合在一個滑動窗口協議裏,我們應該問問自己,在鏈路層這樣做是否正確。帶着這樣的疑問,我們將在第3章(說明X. 2 5網如何用它實現跳到跳的流量控制)和第5章(描述T C P如何用它實現可靠的字節流信道)重新考慮滑動窗口算法。

發佈了35 篇原創文章 · 獲贊 20 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章