1. 程式人生 > >計算機網路之我見-通俗理解計算機網路(六)

計算機網路之我見-通俗理解計算機網路(六)

本篇講解UDP協議

一、UDP協議的組成格式

# UDP協議格式比較簡單,主要由協議頭和協議體構成

# 協議頭由源埠號、目的埠號、校驗和、和包體長度欄位組成

# UDP協議資料包由IP資料包承載,IP資料包頭有兩位元組長度的包體欄位的限制,包體最大長度為65535位元組,所以理論上UDP資料包的長度最大為65535位元組,但是各作業系統的實現不同,一般程式設計中使用的UDP Socket的允許的最大長度都會小於65535位元組

二、UDP協議的不可靠性

1 不可靠性原因分析

# UDP資料報是由IP資料報承載的,IP資料報又是由鏈路層MAC幀承載的,MAC幀的最大長度是有限制的--MTU,一般的MTU都小於1500位元組,所以過長的IP資料報在各節點間傳輸的時候會導致IP分片和重組,分片重組過程可能會導致資料丟失,如下幾種情況:

路由器在等待接收一個分片的IP資料報的所有片的時候定時器超時,路由器並不會給源主機發送任何錯誤通告而是直接丟棄所有收到的資料報片,導致資料丟失

路由器一般都會有資料報轉發緩衝區,如果路由器緩衝區佇列滿了,也會導致路由器直接丟棄所有傳送的IP資料報,導致資料丟失

每個主機的協議棧實現中都會有UDP接收佇列,當在指定埠接收UDP資料包的程序處理不過來的時候,UDP接收佇列滿了,也會丟棄後來的資料報

2 如何減少不可靠性

路由器緩衝區滿這種情況我們可以採取的措施很少,UDP接收佇列滿導致丟失可以通過優化接收程式的程式碼實現來解決,我們可控的是儘量避免分片,如何避免分片?只要把我們傳送的每個UDP包的長度限制在MTU之內就可以,然而到目的地之間的鏈路可能要經過好多跳,每跳線路的MTU我們又無法詳細得到,如何設定資料報大小呢?一種方案是直接選擇比較小的大小,比如512位元組,但是這樣傳輸效率可能會低一點;另一種方案是能夠用一種方式探查到目的主機的線路中的最小MTU大小(一種可行演算法是寫個像上篇所講的“路由跟蹤”程式類似的鏈路MTU探查程式,基本原理是給IP資料包設定不分片標誌,TTL遞增的方式依次傳送一個較大的資料包,鏈路間的路由器發現需要分片而不能分片的錯誤就會向源主機發送ICMP“需要分片”錯誤報告,然後我們減少資料包大小再發送,直到收不到ICMP錯誤報告為止)

三、UDP協議程式設計的注意事項

# 地址複用和埠複用

1 一般我們程式設計時建立一個UDP socket時可以指定繫結的IP和埠號,通常可以指定本機所有的IP(多網絡卡、迴環地址、廣播地址都算多IP)都通配繫結到指定埠,如192.168.0.2 、127.0.0.1都繫結到7777埠上的同一個Socket上,這樣一個socket就可以接收本機的所有網絡卡收上來的埠為7777的UDP資料報

2 如果我們想建立多個socket,每個socket對應一個IP,但是都繫結到同一個埠上,這時就需要在建立socket的時候指定“地址複用”選項來建立(否則作業系統會提示建立失敗),這樣每個socket直接能接收它目的地址為它所繫結的IP的資料報

3 如果我們想建立IP和埠完全相同的多個UDP socket會怎樣?答案是必須同時指定“地址複用”和“埠複用”選項,否者作業系統不會給建立的,收取資料的時候分兩種情況:如果socket繫結的是廣播地址,那麼這幾個socket都會收到相同的資料包的多個拷貝;如果socket繫結的不是廣播地址,那麼一個數據包只交給一個socket處理

額外:對於TCP socket來說,即使指定“地址複用和埠複用”選項也不能同時建立多個繫結IP和埠完全相同的socket!但是對於由於程序意外停止又重啟程序的情況是可以繫結IP和埠完全相同的socket的,區別就是,此前停止的程序所關聯的socket的狀態是time-wait的等待關閉狀態,不是啟用的狀態,不屬於“同時存在的多個IP和埠完全相同的socket”的情況~