深入的理解UDP編程

深入的理解UDP編程深入的理解UDP編程

什麼是UDP?

UDP是User Datagram Protocol(用戶數據報協議)的縮寫,它是一個簡單的協議,簡單到UDP規範RFC0768只有區區3頁。

UDP是工作在IP層之上的傳輸層協議,UDP對IP主要有兩個擴展:

擴展出端口號使得IP數據報可以多路分發到用戶進程。
擴展出校驗和提供網絡傳輸過程中數據差錯的檢驗。
IP提供了一種盡力而爲、無連接的數據報交付服務。IP基於IP地址實現路由和分組轉發,可以將一個IP數據報從網絡的一臺主機傳送到另一臺主機,IP地址決定IP數據報將被送往哪個主機。所以,IP提供主機到主機的數據報傳輸服務。

IP數據報到達目的主機後,內核層實現的IP模塊,會負責接收網卡上的IP數據報,但主機上通常會同時運行多個進程,IP數據報應該交給哪個進程去處理呢?IP搞不定。

端口號(位於UDP首部)決定數據報交給主機上的哪個進程處理。所以,UDP爲端主機上運行的應用程序提供了端到端服務。

UDP的特徵

UDP是無連接的,通信之前無須建連便可直接發送數據報,而TCP是面向連接的。
UDP不提供差錯糾正,但UDP提供差錯檢測(端到端校驗和)。
UDP不做重複消除。
UDP不做流量控制。
UDP不做擁塞控制,沒有協議機制防止高速UDP流量對其他網絡用戶的消極影響。
UDP不保證順序,數據報遞交應用的順序。
UDP不可靠,UDP只負責把應用程序傳給IP層的數據發送出去,並不能保證數據報到達目的地,可靠傳遞需要應用程序去實現。
UDP支持組播交付。
UDP是一種保留消息邊界的傳輸層協議。

消息邊界

應用程序每請求一次UDP輸出將產生一個UDP數據報,從而發送一個IP數據報,而接收端每請求一次UDP接收都將接收一個完整的UDP報(如果有),這跟面向數據流的TCP不一樣。

假設主機A給主機B發送2次數據,第一次4字節“abcd”,第二次3字節“xyz”,而主機B接收2次,分別返回“abcd”、“xyz”兩個消息,也可以返回“xyz”,“abcd”兩個消息(順序不重要),那麼這就是保留消息邊界。

UDP是保留消息邊界的傳輸層協議,利用UDP通信的應用程序每次發送操作會產生一個IP數據報(不考慮分片),這就約束每次發送的數據量不能大於MTU(最大傳輸單元),接收端每次接收都會返回一個個UDP數據報的完整負載,不會出現返回半個數據報負載的情況。

而TCP是不保留消息邊界的流協議,發送端調用發送的次數和每次發送的數據量,跟接收端調用接收的次數和每次接收的數據量,沒有任何對應關係,所以使用TCP的應用程序需要去處理消息邊界。

UDP數據報封裝格式

IPv4協議(Protocol)字段用值17來標識UDP,UDP數據報頭部通常是8字節,IPv4頭部之後緊接着是UDP頭部,然後是UDP數據Payload(如有)。
深入的理解UDP編程深入的理解UDP編程
IPv4封裝包對應的UDP頭部由源端口號、目的端口號、長度、校驗和組成,每個字段都是2字節。
1、端口號,純抽象的標識,它不跟任何物理實體相關
端口號用於幫助協議分辨發送和接收進程。接收端的內核層從網卡接收到IP數據報之後,識別出UDP數據報(IP數據報頭部協議字段值=17)之後,會根據UDP頭部的目的端口號,映射到對應進程,把UDP數據報交給對應的進程去處理,這個映射關係由系統內核管理維護。
深入的理解UDP編程深入的理解UDP編程
目的端口號是必須的,但源端口號是可選的,如果數據報發送者不需要對方回覆的話,則源端口號可被設置爲0。

因爲IP層根據IP頭部的協議類型字段,將進入的IP數據報,分發到特定的傳輸協議(TCP或UDP等),到了傳輸協議層,再根據端口號將協議數據分發到不同進程。所以,端口號是協議獨立的,不同協議的相同端口號並不會引起分發混亂。

比如,一臺機器上的兩個網絡服務進程使用相同的IP地址和端口號,但一個使用TCP協議,另一個使用UDP協議,這樣是沒有問題。

2、長度字段,是以字節爲單位的UDP頭部和UDP數據的總長度,因爲UDP頭部長度爲8,且空數據的UDP數據報是允許的,這意味着該長度字段值最小爲8。UDP長度值是冗餘的,因爲可以通過IP數據報的總長度減去IP首部的長度推導出來。

3、校驗和,覆蓋了UDP首部、UDP數據和一個僞首部,由初始發送方計算,由最終目的方校驗,用於判斷數據報在網絡傳輸過程中是否出錯,比如某一位從1變成了0。

使用UDP的應用程序如何實現可靠傳輸

衆所周知,UDP不可靠、不保證順序。

1、什麼叫不可靠?A給B發送一個UDP數據報,該UDP數據報不一定被正確交付給接收端B,但因爲網絡質量等各種原因,可能丟包,IP數據報是盡力而爲的交付,一切隨緣。

有沒有辦法保證,發送的UDP一定到達目的端?Sorry,保證不了,做不到。

那TCP提供的可靠傳輸是什麼意思?TCP提供的可靠傳輸並不是指不丟包,因爲TCP也依賴IP(IP不可靠)實現數據報交付,TCP的可靠性是指丟掉的包會被重傳,直到被正確投遞,纔會繼續傳輸下一個數據報。

那TCP是怎麼做到可靠傳輸的呢?很簡單,收報確認(ack)+丟包重傳。所以UDP如果要提供可靠傳輸,也可以參考TCP的實現機制,只是TCP是實現在內核層,而基於UDP的應用程序,可以把可靠傳輸做到應用層。要做收報確認+丟包重傳,需要一些額外的信息,比如包序列號之類,可以放到Payload,約定好這些額外信息在Payload中的結構佈局即可。

2、什麼叫不保證順序?A給B發送兩個UDP數據報,兩個UDP數據報會被封裝爲兩個IP數據報,通過IP協議傳輸,因爲兩個IP數據報獨立路由,所以哪個先到?不一定,看心情。

有沒有辦法保證,UDP數據報按照發送端發送的時間順序到達目的端?也Sorry,辦不到。

所以,TCP提供的順序性,其實只是在接收端對IP數據報根據發送順序重新排序,很顯然,UDP要支持重排序,也需要一些額外信息,也只能通過payload攜帶,而不能像TCP一樣(TCP首部的一些字段用於接收端重排序)。

綜上,UDP只提供最簡單端主機上應用程序的端到端服務,其他的特性,如果要提供,那請參考TCP的思路去實現吧。

這是有好處的:因爲簡單,所以開銷很小。而某些應用場景,可以容忍丟包、亂序,UDP就是很適合的。保時捷是很好,但拉磚還是用拖拉機吧。

UDP Socket網絡編程的API不多,socket()用於創建套接字,close()用於關閉套接字,sendto()用於發送數據,recvfrom()用於接收數據。

bind()顧名思義是綁定,TCP可以綁定,UDP也可以,bind用於UDP等於告訴內核:這個套接字跟網絡遠端的一個

而沒有bind之前,只能通過sendto()接口(通過參數指定目的地)。UDP套接字recv()返回的是UDP數據報的數據部分(Payload),不包括UDP數據報首部,這是因爲UDP首部的字段用於分發或者校驗,不需要透傳給應用程序。

使用UDP套接字開發的網絡應用Server/Client,網絡IO相關操作和流程如下圖所示:

深入的理解UDP編程深入的理解UDP編程


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章