如何讓UDP實現可靠傳輸
自定義通訊協議,在應用層定義一些可靠的協議,比如檢測包的順序,重複包等問題,如果沒有收到對方的ACK,重新發包
UDP沒有Delievery Garuantee,也沒有順序保證,所以如果你要求你的資料傳送與接受既要高效,又要保證有序,收包確認等,你就需要在UDP協議上構建自己的協議。比如RTCP,RTP協議就是在UPD協議之上專門為H.323協議簇上的IP電話設計的一種介於傳輸層和應用層之間的協議。
UDP構建可靠資料傳輸
簡單來講,要使用UDP來構建可靠的面向連線的資料傳輸,就要實現類似於TCP協議的超時重傳,有序接受,應答確認,滑動視窗流量控制等機制,等於說要在傳輸層的上一層(或者直接在應用層)實現TCP協議的可靠資料傳輸機制,比如使用UDP資料包+序列號,UDP資料包+時間戳等方法,在伺服器端進行應答確認機制,這樣就會保證不可靠的UDP協議進行可靠的資料傳輸,不過這好像也是一個難題!
(一)可靠性協議
(可靠性協議這部分協議 參考論文《 基於UDP 的可靠檔案傳輸協議設計與實現 》)
首先來設計最為重要的可靠性。在UDP增加報頭前,我們先定義8個位元組的協議頭,為2個位元組的資料包標識,2個位元組的傳送序號,2個位元組的檔案指標定位和2個位元組的資料包中資料大小資訊。資料包標誌指明該資料包為檔案資料包、確認包或者其它控制包,傳送序號用來指明資料包的順序資訊,指標定位位元組資料用來指明該資料包中資料被填寫到檔案的哪個位置,最後的大小資訊也是用來向檔案中讀寫資料時使用。
協議保證可靠性的大致流程是(先只考慮單對單情況下的單方向傳送):
首先發送端傳送一個檔案資訊報文,這個報文就是最簡單的UDP報文,但是裡面的資訊很重要,記錄著檔案的大小,被分隔成的報文數,檔案序號。發完這個資訊包,傳送端阻塞,等待接收端的回覆報文才能繼續。檔案資訊包被接收端接受以後使用確認機制確定是否接受這個檔案,並把決定回饋給傳送端。此時,傳送端如果收到的是“確定接受”的結果,將會把這個檔案的整組資料報全部發送過去,這裡我們並不像最傳統的可靠傳輸協議TCP協議一樣,對於每個每個報文都要確認接受完才會對下一個報文進行處理,太沒效率,遵守本協議的接受端在接受這組報文的時候將遵守錯序重排機制,來對收到的這組報文進行按序號排序,期間可能序號不聯絡不過沒關係,接受過程只要保證序號從小到大即可。傳送端發完所有報文延遲一點時間再發送一個結束報文,延遲時間是為了減少結束報文比資料報文還早被接受的情況,當然即使這種情況出現也不會破壞可靠性,只不過在在結束報文之後的資料報文會被當做丟失的包被要求重發,降低效率。接受端接受到結束報文後按照一開始的檔案資訊包的資訊和序列號做對比,把沒有的序列號的報文的資訊傳回給傳送端,要求重新發送這些報文。傳送端接到資訊以後重發丟失的資料包。直到接收端拿到的報文和資訊匹配,接受端就可以發回一個“接受完畢”的報文。這樣傳送端接受端再進行下一次檔案傳輸。
在這個流程中有幾個重要的機制保證流程的可靠性:
確認機制
本系統接收方並非對任意資料包都進行確認,在下面的一些情況下會使用到該確認機制:
1、接收方收到檔案資訊包時,要對是否接收進行確認。
2、接收方收到結束包時要進行確認,然後檢測該分組內資料包是否丟失。
3、接收方收到全部資料包時要進行確認,以便結束檔案的傳輸過程。
重發機制
協議設計了兩種重發機制:一種是自動重發機制,另一種是請求重發機制。自動重發機制是訊息傳送時啟動一個定時器,如果在規定的一段時間內未收到接收方的確認訊息,則斷定這段時間內傳送的報文已經丟失並進行重發。請求重發機制則是在接收方收到傳送方發來的傳輸結束訊息後,在接收方對收到的所有報文序號進行檢測,如果發現某些序號的報文缺失,接收方主動請求重發缺失的序號對應的報文。具體實現設計如下所述:
1、自動重發機制
通訊傳送方和接收方都維持一個自動重發定時器,在通訊開始前會檢查自動重發定時器是否啟動,如果沒有啟動,就會啟動這個定時器。如果在一個特定時間間隔內傳送方沒有收到來自接收方的任何確認訊息,或者接收方沒有到傳送方的通道檢測報文。這時系統會將這個定時器歸零,並將這段時間內傳送的訊息重發一遍,把記錄重發次數變數加1。如果過在規定的時間內依然沒有收到對方的任何確認資訊,則重新將定時器歸0, 執行重發操作並將重發次數加1,如此迴圈,在重發次數未達到指定資料之前,直到收到對方的一個確認訊息,然後停止自動重發定時器,將重發次數清 0;否則證明傳輸路徑出現問題。
2、請求重發機制
接收方記錄著已收到資料包的序列以及未收到的資料包序列。當接收到分組結束包時,接收方就會啟動定時器,檢索該分組內未收到的資料包,如果資料包已全部接收到,則關閉定時器,進行下一個分組的傳輸。否則查詢丟失 資料包的序號並依次傳送請求重發資料包,在規定時間內接收發送方重發的資料包,然後定時器歸 0,重新檢索未收到資料包,並按上述情況做出反應,如此迴圈往復,直到最終完成該分組的傳輸過程。
協議的錯序重排機制
協議頭結構中有2個位元組的序號欄位,當傳送端接收到對端傳送的確認接收報文後,開始讀取檔案資料塊內容寫入協議資料區,為每一個數據塊編制一個序號,序號的最大值要求與接收端維護的一個為了實現錯序重排機制的動態表長度一致。序號排滿後,後面的報文會在下一個分組中進行傳送。這時傳送端 會根據當前分組下讀取的資料塊大小及起始位置填寫協議頭中的欄位,最後將資料包傳送出去。接收端起初會生成一個動態陣列用來儲存接收到的資料包序號,當接收端準備好接收檔案後將陣列的每一位置為無效,每收到一個數據包,就會讀取其序號欄位值並將陣列相應位置為有效,然後將資料區的內容寫入檔案。這樣即使由於網路狀況導致資料包不能按序到達,接收端也能根據資料包位置欄位和大小欄位將資料寫入檔案。序號欄位在收到結束包後用於檢索動態陣列啟動請求重傳機制。
(二)多使用者併發訪問和檔案下載協議
前面我們說UDP是面向無連線的,這樣一來就可以打破一對一連線的狀態,使得一臺伺服器可以向多個客戶端傳輸相同資訊。
所以我們如何利用它來實現多使用者併發訪問和檔案下載呢?本協議中,首先發送方會開闢一個空間,這個空間儲存著傳送端有的各個檔案的序號和可能出現的接收方希望得到某個序號檔案的ip地址埠號等資訊。在傳送端開始運作之後,就會有一個程序一直在監聽是否有對某個檔案的請求,如果有就把請求方的資訊儲存在這個空間裡。假如請求某個檔案的ip+埠只有一個,那麼這個協議是沒有實質性作用。然而一旦短時間內有大量的ip請求這個檔案,那麼在某次我們上邊設計的可靠性協議的傳輸過程中,就可以好好利用這個時間差,下一段具體說明。除此之外還有一個很人性化的設計可以加入到這裡,就是可以在監聽到某次請求時向對方返回目前的伺服器狀況,比如對應檔案的等待ip有多少,這樣讓接受方決定狀況比較擁堵時候是否等一下再請求。
具體來說,我們每次傳送檔案資訊報文時,在多個接收方請求的情況下將是一組一組傳送的,把目前在等待空間的所有(或者限制一個上限個數10個)接收方都發送檔案資訊報文。收到的同意接受報文後把這些同意接受的資訊記錄下來,將檔案報文組和傳送完畢的報文同時傳送給這些接受方,再把各個接收方返回的缺失報文記錄下來,再重傳。
非常重要的一點是,其實對於接受方來說在檔案傳輸過程中並沒有什麼多餘的動作,它要做的和只有他一個接收方的情況沒有任何的不同,可能只是整個過程的流暢性會受影響。需要變動的主要是傳送方,它在做好可靠性協議要求的幾點之外,還要做好一系列的記錄操作,保證整個過程不會亂套。
(三)針對下載的檔案大小不應有限制設計的協議
回答問題時候其實就把思路講完全了,對於一份任意大小的檔案,我們都是可以透過切分成固定大小的N個報文然後將他們組成一組傳送的。在每次組報文傳輸過程之前傳輸的檔案資訊報文也是這個過程之一,它記錄了本次檔案的大小,被分成的報文數量,每個報文的大小(通常確定的大小)。這種方法下,不管多大的檔案都視作一定數量的報文,只要傳送方和接受方在資訊報文中確定了資訊,檔案大小就沒有限制
所以,利用上邊設計的可靠性協議、多使用者併發訪問和檔案下載協議和針對下載的檔案大小不應有限制設計的協議,我們就能實現一個可靠的檔案傳輸協議,並滿足以下要求:1)下層使用不可靠的UDP服務(即使用資料報方式的套接字);2)能夠支援多使用者併發訪問和檔案下載;3)下載的檔案大小不應有限制。
如何讓UDP實現可靠傳輸
自定義通訊協議,在應用層定義一些可靠的協議,比如檢測包的順序,重複包等問題,如果沒有收到對方的ACK,重新發包
UDP沒有Delievery Garuantee,也沒有順序保證,所以如果你要求你的資料傳送與接受既要高效,又要保證有序,收包確認等,你就需要在UDP協議上構建自己的協議。比如RTCP,RTP協議就是在UPD協議之上專門為H.323協議簇上的IP電話設計的一種介於傳輸層和應用層之間的協議。
UDP構建可靠資料傳輸
簡單來講,要使用UDP來構建可靠的面向連線的資料傳輸,就要實現類似於TCP協議的超時重傳,有序接受,應答確認,滑動視窗流量控制等機制,等於說要在傳輸層的上一層(或者直接在應用層)實現TCP協議的可靠資料傳輸機制,比如使用UDP資料包+序列號,UDP資料包+時間戳等方法,在伺服器端進行應答確認機制,這樣就會保證不可靠的UDP協議進行可靠的資料傳輸,不過這好像也是一個難題!
(一)可靠性協議
(可靠性協議這部分協議 參考論文《 基於UDP 的可靠檔案傳輸協議設計與實現 》)
首先來設計最為重要的可靠性。在UDP增加報頭前,我們先定義8個位元組的協議頭,為2個位元組的資料包標識,2個位元組的傳送序號,2個位元組的檔案指標定位和2個位元組的資料包中資料大小資訊。資料包標誌指明該資料包為檔案資料包、確認包或者其它控制包,傳送序號用來指明資料包的順序資訊,指標定位位元組資料用來指明該資料包中資料被填寫到檔案的哪個位置,最後的大小資訊也是用來向檔案中讀寫資料時使用。
協議保證可靠性的大致流程是(先只考慮單對單情況下的單方向傳送):
首先發送端傳送一個檔案資訊報文,這個報文就是最簡單的UDP報文,但是裡面的資訊很重要,記錄著檔案的大小,被分隔成的報文數,檔案序號。發完這個資訊包,傳送端阻塞,等待接收端的回覆報文才能繼續。檔案資訊包被接收端接受以後使用確認機制確定是否接受這個檔案,並把決定回饋給傳送端。此時,傳送端如果收到的是“確定接受”的結果,將會把這個檔案的整組資料報全部發送過去,這裡我們並不像最傳統的可靠傳輸協議TCP協議一樣,對於每個每個報文都要確認接受完才會對下一個報文進行處理,太沒效率,遵守本協議的接受端在接受這組報文的時候將遵守錯序重排機制,來對收到的這組報文進行按序號排序,期間可能序號不聯絡不過沒關係,接受過程只要保證序號從小到大即可。傳送端發完所有報文延遲一點時間再發送一個結束報文,延遲時間是為了減少結束報文比資料報文還早被接受的情況,當然即使這種情況出現也不會破壞可靠性,只不過在在結束報文之後的資料報文會被當做丟失的包被要求重發,降低效率。接受端接受到結束報文後按照一開始的檔案資訊包的資訊和序列號做對比,把沒有的序列號的報文的資訊傳回給傳送端,要求重新發送這些報文。傳送端接到資訊以後重發丟失的資料包。直到接收端拿到的報文和資訊匹配,接受端就可以發回一個“接受完畢”的報文。這樣傳送端接受端再進行下一次檔案傳輸。
在這個流程中有幾個重要的機制保證流程的可靠性:
確認機制
本系統接收方並非對任意資料包都進行確認,在下面的一些情況下會使用到該確認機制:
1、接收方收到檔案資訊包時,要對是否接收進行確認。
2、接收方收到結束包時要進行確認,然後檢測該分組內資料包是否丟失。
3、接收方收到全部資料包時要進行確認,以便結束檔案的傳輸過程。
重發機制
協議設計了兩種重發機制:一種是自動重發機制,另一種是請求重發機制。自動重發機制是訊息傳送時啟動一個定時器,如果在規定的一段時間內未收到接收方的確認訊息,則斷定這段時間內傳送的報文已經丟失並進行重發。請求重發機制則是在接收方收到傳送方發來的傳輸結束訊息後,在接收方對收到的所有報文序號進行檢測,如果發現某些序號的報文缺失,接收方主動請求重發缺失的序號對應的報文。具體實現設計如下所述:
1、自動重發機制
通訊傳送方和接收方都維持一個自動重發定時器,在通訊開始前會檢查自動重發定時器是否啟動,如果沒有啟動,就會啟動這個定時器。如果在一個特定時間間隔內傳送方沒有收到來自接收方的任何確認訊息,或者接收方沒有到傳送方的通道檢測報文。這時系統會將這個定時器歸零,並將這段時間內傳送的訊息重發一遍,把記錄重發次數變數加1。如果過在規定的時間內依然沒有收到對方的任何確認資訊,則重新將定時器歸0, 執行重發操作並將重發次數加1,如此迴圈,在重發次數未達到指定資料之前,直到收到對方的一個確認訊息,然後停止自動重發定時器,將重發次數清 0;否則證明傳輸路徑出現問題。
2、請求重發機制
接收方記錄著已收到資料包的序列以及未收到的資料包序列。當接收到分組結束包時,接收方就會啟動定時器,檢索該分組內未收到的資料包,如果資料包已全部接收到,則關閉定時器,進行下一個分組的傳輸。否則查詢丟失 資料包的序號並依次傳送請求重發資料包,在規定時間內接收發送方重發的資料包,然後定時器歸 0,重新檢索未收到資料包,並按上述情況做出反應,如此迴圈往復,直到最終完成該分組的傳輸過程。
協議的錯序重排機制
協議頭結構中有2個位元組的序號欄位,當傳送端接收到對端傳送的確認接收報文後,開始讀取檔案資料塊內容寫入協議資料區,為每一個數據塊編制一個序號,序號的最大值要求與接收端維護的一個為了實現錯序重排機制的動態表長度一致。序號排滿後,後面的報文會在下一個分組中進行傳送。這時傳送端 會根據當前分組下讀取的資料塊大小及起始位置填寫協議頭中的欄位,最後將資料包傳送出去。接收端起初會生成一個動態陣列用來儲存接收到的資料包序號,當接收端準備好接收檔案後將陣列的每一位置為無效,每收到一個數據包,就會讀取其序號欄位值並將陣列相應位置為有效,然後將資料區的內容寫入檔案。這樣即使由於網路狀況導致資料包不能按序到達,接收端也能根據資料包位置欄位和大小欄位將資料寫入檔案。序號欄位在收到結束包後用於檢索動態陣列啟動請求重傳機制。
(二)多使用者併發訪問和檔案下載協議
前面我們說UDP是面向無連線的,這樣一來就可以打破一對一連線的狀態,使得一臺伺服器可以向多個客戶端傳輸相同資訊。
所以我們如何利用它來實現多使用者併發訪問和檔案下載呢?本協議中,首先發送方會開闢一個空間,這個空間儲存著傳送端有的各個檔案的序號和可能出現的接收方希望得到某個序號檔案的ip地址埠號等資訊。在傳送端開始運作之後,就會有一個程序一直在監聽是否有對某個檔案的請求,如果有就把請求方的資訊儲存在這個空間裡。假如請求某個檔案的ip+埠只有一個,那麼這個協議是沒有實質性作用。然而一旦短時間內有大量的ip請求這個檔案,那麼在某次我們上邊設計的可靠性協議的傳輸過程中,就可以好好利用這個時間差,下一段具體說明。除此之外還有一個很人性化的設計可以加入到這裡,就是可以在監聽到某次請求時向對方返回目前的伺服器狀況,比如對應檔案的等待ip有多少,這樣讓接受方決定狀況比較擁堵時候是否等一下再請求。
具體來說,我們每次傳送檔案資訊報文時,在多個接收方請求的情況下將是一組一組傳送的,把目前在等待空間的所有(或者限制一個上限個數10個)接收方都發送檔案資訊報文。收到的同意接受報文後把這些同意接受的資訊記錄下來,將檔案報文組和傳送完畢的報文同時傳送給這些接受方,再把各個接收方返回的缺失報文記錄下來,再重傳。
非常重要的一點是,其實對於接受方來說在檔案傳輸過程中並沒有什麼多餘的動作,它要做的和只有他一個接收方的情況沒有任何的不同,可能只是整個過程的流暢性會受影響。需要變動的主要是傳送方,它在做好可靠性協議要求的幾點之外,還要做好一系列的記錄操作,保證整個過程不會亂套。
(三)針對下載的檔案大小不應有限制設計的協議
回答問題時候其實就把思路講完全了,對於一份任意大小的檔案,我們都是可以透過切分成固定大小的N個報文然後將他們組成一組傳送的。在每次組報文傳輸過程之前傳輸的檔案資訊報文也是這個過程之一,它記錄了本次檔案的大小,被分成的報文數量,每個報文的大小(通常確定的大小)。這種方法下,不管多大的檔案都視作一定數量的報文,只要傳送方和接受方在資訊報文中確定了資訊,檔案大小就沒有限制
所以,利用上邊設計的可靠性協議、多使用者併發訪問和檔案下載協議和針對下載的檔案大小不應有限制設計的協議,我們就能實現一個可靠的檔案傳輸協議,並滿足以下要求:1)下層使用不可靠的UDP服務(即使用資料報方式的套接字);2)能夠支援多使用者併發訪問和檔案下載;3)下載的檔案大小不應有限制。