1980年8月,緊隨TCP/IP之后,UDP(User Datagram Protocol,用戶數據報協議)備John Postel加入了核心網絡協議套件。UDP經常被稱為無協議。
. 數據報
一個完整、獨立的數據實體,攜帶著從源節(jié)點到目的地節(jié)點的足夠信息,對這些節(jié)點間之前的數據交換和傳輸網絡沒有任何依賴。
數據報和分組是兩個機場被人混用的詞,實際上他們還是有區(qū)別的。分組可以用來代任何格式化的數據塊,而數據報則通常只用來描述那些通過不可靠的服務傳輸的分組,既不保證送達,也不發(fā)送失敗通知。正因為如此,UDP就成了“不可靠數據報協議”;
3.1 無狀態(tài)服務
要理解為什么UDP被人稱作“無協議”,必須從作為TCP和UDP下一層的ip協議說起。IP層的主要任務就是按照地址從源主機向目標主機發(fā)送數據報。 為此,消息會被封裝在一個IP分組內,其中載明了原地址和目標地址,以及其他一些路有參數。注意,數據報這個詞暗示了一個重要的信息:IP層不保證信息可靠的支付,也不發(fā)送失敗通知,實際上是把底層網絡的不可靠性直接暴露給了上一層。如果某個路由節(jié)點因為網絡擁塞、負載過高或其他原因而刪除了IP分組,那么在必要的情況下,IP的上一層協議要負責檢測、恢復和重發(fā)數據。
UDP協議會用自己的分組結構封裝用戶信息,他只增加了4個字段:源端口、目標端口、分組長度和校驗和。這樣當IP把分組送達目標主機時,該主機能夠拆開UDP分組,根據目標端口找到目標應用程序,然后再把消息發(fā)送過去而已。
事實上,UDP數據報中的源端口和校驗和字段都是可選的。IP分組的首部也有校驗和,應用程序可以忽略UDP校驗和。也就是說,所有錯誤檢測和錯誤糾正工作都可以委托給上層的應用程序。說到底,UDP僅僅是在IP層之上通過嵌入應用程序的源端口和目標端口,提供了一個”應用多路復用“機制。明白了這一點,就可以總結一下UDP的無服務是怎么回事了。
. 不保證消息交付
不確認,不重傳,無超時。
. 不保證交付順序
不設置保序號,不重排,不會發(fā)生隊首阻塞。
. 不跟蹤連接狀態(tài)
不必建立連接或重啟狀態(tài)機。
. 不需要擁塞控制
不內置客戶端或網絡反饋機制
TCP是一個面向字節(jié)流的協議,能夠以多個分組形式發(fā)送應用程序消息,且對分組中的消息范圍沒有任何明確限制。因此,連接的兩端存在一個連接狀態(tài),每個分組都有序號,丟失還要重發(fā),并且要按順序交付。相對來說,UDP數據報有明確的限制:數據報必須封裝在IP分組中,應用程序必須讀去讀取完整的消息。換句話說,數據報不能分片。
UDP是一個簡單、無狀態(tài)的協議,適合作為其他上層應用協議的輔助。實際上,這個協議的所有決定都需要由上層的應用程序作出。不過,再急著去實現一個協議來扮演TCP的角色之前,你還應該認真想一想這里涉及的復雜細節(jié),比如UDP要與很多中間設備打交道(NAT穿透),再想一想設計網絡協議的那些最佳實踐。如果沒有周密的設計和規(guī)劃,一流的構想也可能淪為二流的TCP實現。TCP中的算法和狀態(tài)機已經經過了幾十年的磨合與改進,而且吸收幾十種并不那么容易重新實現的機制。
3.2 UDP與網絡地址轉換器
令人遺憾的是,IPv4地址只有32位長,因而最多只能提供42.9億個唯一的IP地址。1990年代初,互聯網上的主機數量呈指數增長,但不可能所有主機都分配一個唯一的IP地址。1994年作為解決IPv4地址即將耗盡的一個臨時性的方案,IP網絡地址轉換器(NAT,Network Address Translator)規(guī)范出臺了,這就是RFC1631.
建議的IP重用方案就是在網絡邊緣加入NAT設備,每個NAT設備負責維護一個表,表中包含本地IP和端口到全球唯一(外網)IP和端口的映射。這樣NAT設備背后的IP地址空間就可以在各種不同的網絡中得到重用,從而解決地址耗盡問題。
3.2.1 連接狀態(tài)超時
NAT轉換的問題(至少對于UDP而言)在于必須維護一份精確的路由表才能保證數據轉發(fā)。NAT設備依賴連接狀態(tài),而UDP沒有狀態(tài).這種根本 上的錯配是很多UDP數據報傳輸問題的總根源。況且,客戶端前面有很多個NAT設備的情況也不鮮見,問題由此進一步惡化了。
每個TCP連接都有一個設計周密的協議狀態(tài)機,從握手開始,然后傳輸應用數據,最后通過明確的信號確認關閉連接。在這種設計下,路由設備可以監(jiān)控連接狀態(tài),根據情況創(chuàng)建或刪除路由表中的條目。而UDP呢,沒有握手,么有連接終止,實際根本沒有可監(jiān)控的連接狀態(tài)機。
發(fā)送出站UDP不費事,但路由響應卻需要轉化表中有一個條目能告訴我們本地目標主機的IP和端口。因此,轉換器必須保存每個UDP流的狀態(tài),而UDP自身卻沒有狀態(tài)。
更糟糕的是,NAT設備還被賦予了刪除轉換記錄的責任,但由于UDP沒有連接終止確認環(huán)節(jié),任何一端隨時都可以停止傳輸數據報,而不必發(fā)送通告。為解決這個問題,UDP路由記錄會定時過期。定是多長?沒有規(guī)定,完全取決于轉換器的制造商、型號、版本和配置。因此,對于較長時間的UDP通信,有一個事實上的最佳做法,即引入一個雙向keep-alive分組,周期性地重置傳輸路徑上所有NAT設備中轉換記錄的計時器。
TCP超時和NAT
從技術角度講,NAT設備不需要額外的TCP超時機制。TCP協議就遵循一個設計嚴密的握手與終止過程,通過這個過程就可以確定何時需要添加或刪除轉換記錄。遺憾的是,實際應用中NAT設備給TCP和UDP會話應用了類似的超時邏輯。
這樣就導致了TCP連接有時候也需要雙向keep-alive分組。如果你的TCP連接突然斷開,那很有可能就是中間NAT超時造成的。
3.2.2 NAT穿透
不可預測的連接狀態(tài)處理是NAT設備帶來的一個嚴重問題,但更為嚴重的則是很多應用程序根本就不能建立UDP連接。尤其是P2P應用程序,涉及VoIP、游戲和文件共享等,它們客戶端與服務器經常需要角色互換,以實現端到端的雙向通信。
NAT帶來的第一個問題,就是內部客戶端不知道外網IP地址,只知道內網IP地址。NAT負責重寫每個UDP分組中的源端口、地址,以及IP分組中的源IP地址。如果客戶端在應用數據中以其內網IP地址與外網主機通信,連接必然失敗。所謂的“透明”轉換因此也就成了一句空話,如果應用程序想與私有網絡外部的主機通信,那么它首先必須知道自己的外網IP地址。
然而,知道外網IP地址還不是實現UDP傳輸的充分條件。任何到達NAT設備外網IP的分組還必須有一個目標端口,而且NAT轉換表中也要有一個條目可以將其轉換為內部主機的IP地址和端口號。如果沒有這個條目(通常是從外網傳數據進來),那到達的分組就會被刪除。此時的NAT設備就像一個分組過濾器,除非用戶通過端口轉發(fā)(映射)或類似機制配置過,否則它無法確定將分組發(fā)送給那臺主機。
需要注意的是,上述行為對客戶端應用程序不是問題??蛻舳藨贸绦蚧趦炔烤W絡實現交互,會在交互期間建立必要的轉換記錄。不過,如果隔著NAT設備,那客戶端(作為服務器)處理來這P2P應用程序(VoIP、游戲、文件共享)的入站連接時,就必須面向NAT穿透問題。
為解決UDP與NAT的這種不搭配,人們發(fā)明了很多穿透技術(TURN、STUN、ICE),用于在UDP主機之間建立端到端的連接。
3.2.3 STUN、TURN與ICE
STUN(Session Traversal Utilities for NAT)是一個協議(RFC 5389),可以讓應用程序發(fā)現網絡中的地址轉換器,發(fā)現之后進一步取得為當前連接分配的內網IP地址和端口。為此,這個協議需要一個已知的第三方STUN服務支持,該服務器必須假設在公網上。
假設STUN服務器的IP地址已知(通過DNS查找或手工指定),應用程序首先向STUN服務器發(fā)送一個綁定請求。然后,STUN服務器返回一個響應,其中包含在外網中代表客戶端的IP地址和端口號。這種簡單的方式解決了前面討論的一些問題。
. 應用程序可以獲得外網IP和端口,并利用這些信息與對端通信;
. 發(fā)送到STUN服務器的出站綁定請求將在通信要經過的NAT中建立路由條目,使得到達該IP和端口的入站分組可以找到內網中的應用程序;
. STUN協議定義了一個簡單keep-alive探測機制,可以保證NAT路由條目不超時。
有了這個機制,兩臺主機端需要通過UDP通信時,它們首先都會向各自的STUN服務器發(fā)送綁定請求,然后分別使用響應中的外網IP地址和端口號交換數據。
但在實際應用中,STUN并不能適應所有類型的NAT和網絡配置。不僅如此,某些情況下UDP還會被防火墻或其他網絡設備完全屏蔽。這種情況在很多企業(yè)網很常見。為解決這個問題,在STUN失敗的情況下,我們還可以使用TURN協議作為后備。TURN可以在最壞的情況下跳過UDP而且換到TCP。
TURN中的關鍵詞當然是中繼。這個協議依賴于外網中繼設備在兩端間傳遞數據。
. 兩端都要向同一臺TURN服務器發(fā)送分配請求來建立連接,然后在進行權限協商。
. 協商完畢,兩端都把數據發(fā)送到TURN服務器,再由TURN服務器轉發(fā),從而實現通信。
很明顯,這就不再是端對端的數據交換了!TURN是任何網絡中為兩端提供連接的最可靠方式,但運維TURN服務器的投入也很大。至少,為滿足傳輸數據的需要,中繼設備的容量必須足夠大,因此,最好在其他直連手段都失敗的情況下,再使用TURN。
建立高效的NAT穿透方案可不容易。好在,我們還有ICE協議。ICE規(guī)定了一套方法,致力于在通信隔斷之間建立一條有效的通道:能直連就直連,必要時STUN協商,再不行使用TURN。
3.3 針對UDP的優(yōu)化建議
UDP是一個簡單常用的協議,經常用于引導其他傳輸協議。事實上,UDP的特色在于她所省略的那些功能:連接狀態(tài)、握手、重發(fā)、重組、重排、擁塞控制、擁塞預防、流量控制,甚至可選的錯誤檢測,統統沒有。這個面向消息的最簡單的傳輸層在提供靈活性的同時,也給實現者帶來了麻煩。
與內置流量和擁塞控制以及擁塞預防的TCP不同,UDP應用程序必須自己實現這些機制。擁塞處理做的不到位的UDP應用程序很容易堵塞網絡,造成網路性能下降,嚴重時還會導致網絡擁塞崩潰。如果你想在自己的應用程序中使用UDP,務必要認真研究和學習當下的最佳實踐和建議。RFC 5405就是這么一份文檔,它對設計單播UDP應用程序給出了很多設計建議,簡述如下:
. 應用程序必須容忍各種因特網路徑條件
. 應用程序應該控制傳輸速度
. 應用程序應該對所有流量進行擁塞控制
. 應用程序應該使用與TCP相近的帶寬
. 應用程序應該準備基于丟包的重發(fā)計數器
. 應用程序應該不發(fā)送大于路徑MTU的數據表
. 應用程序應該處理數據報丟失、重復和重排
. 應用程序應該足夠穩(wěn)定以支持2分鐘以上的交付延遲
. 應用程序應該支持IPv4 UDP校驗和,必須支持IPv6校驗和
. 應用程序可以在需要時使用keep-alive(最小間隔15秒)
設計新傳輸協議必須經過周密的考慮、規(guī)劃和研究,否則就是不負責任。要盡可能利用已有的庫或框架,這個庫或框架應該考慮了NAT穿透,而且能夠與其他并發(fā)的網絡流量和諧共存。
第三章 UDP的構成
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
相關閱讀更多精彩內容
- 18.1 引言 TCP是一個面向連接的協議。無論哪一方向另一方發(fā)送數據之前,都必須先在雙方之間建立一條連接。本章將...