We read the world wrong but say that it deceives us.編程
"咱們看錯了世界,卻說世界欺騙了咱們"緩存
參考資料:TCP/IP入門經典 (第五版)服務器
1、簡介socket
UDP(User Datagram Protocol,用戶數據報協議),是一個簡單的面向數據報的傳輸層協議,進程的每一個輸出操做都正好產生一個UDP數據報,並組裝成一份待發送的IP數據報。它在協議棧中的位置以下函數
特色:UDP是一個面向數據報的協議,因此它不提供可靠性:它把應用程序傳給IP層的數據發送出去,但並不保證它們能到達目的地spa
2、UDP首部設計
因爲不提供可靠性,因此UDP的首部比較簡單blog
各字段含義以下:接口
● 端口號:就是傳輸層識別應用程序的一個正整數
● 16位UDP長度:UDP長度指的是UDP首部和UDP數據的總長度。注意,UDP長度的最小值爲8字節,也就是說能夠發送一個沒有數據的UDP數據報。記得在 TCP/IP協議-IP協議 中說到IP首部中有一個首部長度,那麼用IP數據報的總長減去IP首部的長度就能夠獲得UDP數據報的長度了
● 16位UDP檢驗和:關於檢驗和,要特別留意幾點。
首先,UDP的檢驗和覆蓋了UDP首部和UDP數據,而IP首部的檢驗和只覆蓋了IP首部;其次,UDP的檢驗和是可選的,而TCP的檢驗和是必須的;UDP數據報的長度能夠是奇數字節,因此在計算時要在末尾填充0,可是這些0可能不被傳送;UDP檢驗和的計算方法與IP首部的檢驗和同樣(16個bit的二進制反碼求和)
最後,UDP在計算檢驗和的時候包含了一個12字節長的僞首部,它僅僅是爲了計算檢驗和而設置。UDP檢驗和計算過程當中使用的各個字段以下
若是檢驗和的計算結果爲0,則存入的值全爲1。若是傳送的檢驗和爲0,說明發送端沒有計算檢驗和。這樣,若是接收端計算的檢驗和不爲全0,可是檢驗和字段爲全0的話,說明傳送過程當中出錯了,UDP數據報將會被丟棄,而且不產生任何差錯報文
雖然UDP檢驗和是可選的,可是它們應該老是在用,畢竟仍是要確報數據傳輸的正確性
3、IP分片和重組
爲何要在這裏討論IP分片呢?前面講到UDP是不提供傳輸的可靠性的,可是至少要保證數據能完整的傳輸,因此只能把這個責任留給IP。下面先來了解幾個概念
最大UDP數據報長度
IP數據報的最大長度爲65535個字節,去掉IP首部的20個字節和UDP首部的8個字節,UDP數據報的最大長度理論上應該爲65507字節。但事實上,大多數實現都達不到這個長度,緣由有下:
● 應用程序接口限制:socket API提供了一個可供應用程序調用的函數,用來設置接收和發送緩存的長度,大部分系統都默認提供了可讀寫大於8192字節的UDP數據報。
● 內核實現:可能存在一些實現特性(或差錯),使IP數據報長度小於65535
雖然IP能夠發送那麼長的數據報,但應用程序並不保證可以讀取該長度的數據。所以,UDP編程接口容許應用程序設置能處理的最大長度。當數據報長度超出應用程序能處理的最大長度時,不一樣的API有着不一樣的處理策略,這就要求發送端控制數據報的大小
路徑MTU
MTU(最大傳輸單元),指的是數據鏈路層對傳輸的數據幀長度的一個上限值,不一樣的網絡類型有着不一樣的值。而路徑MTU指的是兩臺通訊主機路徑中最小的MTU。兩臺主機之間的路徑MTU不必定是一個常數,由於路由選擇並不必定是對稱的,並且網絡隨時都在發生變化
ICMP
ICMP(Internet控制報文協議),是一個位於網絡層的協議。它常常被認爲是IP層的一個組成部分,由於ICMP的主要功能是傳遞差錯報文及其餘須要注意的信息,而且ICMP報文是封裝在IP數據報內部的
常見的幾種差錯報文:
● 端口不可達:若是接收端收到一份UDP數據報而目的端口與某個正在使用的進程不相符,那麼UDP返回一個ICMP不可達報文
● 分片衝突不可達:當路由器收到一份須要分片的數據報,而在IP首部又設置了不分片的標誌位,那麼路由器返回一個ICMP不可達報文。而且,此時能夠把這條路徑的路徑MTU返回給源主機或路由器,這樣就能夠幫助這條路徑上的其餘路由器肯定每一個子路徑上的MTU,這被稱做路徑MTU發現機制
● 源站抑制:當一個系統(路由器或主機)接收數據報的速度比其處理速度快時,它有可能會返回一個源站抑制差錯報文。因爲源站抑制須要消耗帶寬,而且實際上沒有什麼做用,因此人們並不支持產生源站抑制報文
IP分片
前面已經講過,數據鏈路層通常要限制每次發送數據幀的最大長度(MTU)。任什麼時候候IP層接收到一份要發送的IP數據報時,它要判斷向本地哪一個接口發送數據(選路),並查詢接口得到MTU,若是數據報長度大於MTU,那就須要進行分片。分片能夠發生在原始發送端主機上,也能夠發生在中間路由器上。
在介紹IP首部字段的時候,談到IP首部的「第二行」有三個字段:16位標識、3位標誌和13位片偏移,它們就是被用在IP分片過程當中。對於發送端發送的每份IP數據報來講,其標識字段都包含一個惟一值,在數據報分片時被複制到每一個片中,代表它們是來自同一個數據報。標誌字段用其中一個bit來表示「更多的片」,把該位置1表示這個還有其餘分片,因此最後一片要把該位置0。片偏移字段指的是該片偏移原始數據報開始處的位置。另外,分片之後,每一個片的總長度值要改成該片的長度值。標誌字段中有一個bit稱做「不分片」位,若是將這個置1,IP將不對數據報進行分片。若是此時致使數據報不能發送,那麼將會返回一個ICMP不可達差錯報文(分片衝突)
分片以後,每一片都成爲一個分組,這裏的分組指的是網絡層到數據鏈路層之間的傳輸單元,而IP數據報是指IP層端到端的傳輸單元。每一個分組都有本身的IP首部
須要注意是:
● 在分片時,除最後一個片外,其餘每個片中的數據部分(除IP首部外的其他部分)必須是8字節的整數倍(暫時沒搞清楚爲何,我的猜想是爲了方便計算片偏移,還有接收端的重組)
● 任何傳輸層首部只出如今第一片數據中
● 分片可能發生在源主機或者路徑上的路由器,但重組只可能發生在目的主機上。由於路徑上的路由器只負責轉發,並不關心IP數據報的數據內容
● 即便只丟失了一片數據也須要從新傳整個數據報,由於上一點,中間路由器可能再次分片,而目的端並不知道丟失的片是被如何分片的
● 各個片到達目的端時多是亂序的,可是IP首部利用前面講的三個字段,能夠將分片正確地拼接起來
下面來完整描述一個IP數據報的傳輸過程做爲總結,假設待發送的傳輸層數據報須要進行分片,而且發送端和接收端不是直接相連:
①源主機的傳輸層將數據報發送到網絡層;
分片:②
②IP發現數據報太大,須要分片,就將數據報分片:第一片包含了數據報的開頭部分數據,數據大小爲8字節的整數倍,包含了傳輸層首部,並將標誌字段中表示「更多的片」字段置1,片偏移字段置0,而後把總長度值改成分片之後的片長度值;第二片到倒數第二片包含了某個長度的數據,而且數據大小爲8字節的整數倍,可是它們都沒有包含傳輸層首部,它們的「更多的片」字段置爲1,片偏移字段根據片序號和前一片的數據長度設置,總長度設置同第一片;最後一片包含了剩餘的數據部分,數據長度不必定是8字節的整數倍,沒有包含傳輸層首部,「更多的片」字段被置0,片偏移字段根據前面的數據長度設置,總長度值也根據前面的片進行設置;全部片的標識字段都相同
③網絡層把每個片做爲一個分組傳送給數據鏈路層;
傳輸:④~⑥
④數據鏈路層將分組轉化爲數據幀發送給下一個系統(路由器或者主機);
⑤接收到數據幀的路由器向上傳送至網絡層;
⑥IP檢查數據報長度和MTU,若是須要分片,就跳到第②步;若是不須要分片,就跳到第④步,直到發送到目的主機;
重組:⑦
⑦目的主機陸續收到各個片,若是目的主機發現缺失了某個片,那麼將會返回一個ICMP錯誤報文,源主機將會從新發送數據報,回到第①步;若是沒有片缺失,目的主機將會根據標識字段、標誌字段和片偏移將全部片重組爲傳輸層數據報,傳輸層發送給應用程序,數據傳輸完成
關於IP分片重組的實現,能夠參考 Linux TCP/IP協議棧關於IP分片重組的實現
4、UDP服務器設計
最後來討論一下UDP那些影響使用該協議的服務器的設計和實現方面的協議特性
客戶IP地址及端口號
UDP服務器必須保存來自客戶數據報的源IP地址和源端口號,這個特性容許一個交互UDP服務器對多個客戶進行處理
目的IP地址
某些應用程序須要知道數據報是發送給誰的,即目的IP地址
UDP輸入隊列
大多數UDP服務器是重複型服務器,單個服務器進程對單個UDP端口上的全部客戶請求進行處理。因此必須維護一個輸入隊列來對差很少同時到達的請求進行處理
限制本地IP地址
大多數UDP服務器在建立UDP端點是都使其IP地址具備通配符的特色,這樣能夠從任何的本地接口來接收用戶請求
限制遠端IP地址
限制遠端IP地址和端口號能夠只接收特定地址的UDP數據報
每一個端口有多個接收者
當UDP數據報到達目的IP地址爲廣播或多播地址,並且在目的IP地址和端口號處有多個端點時,就向每一個端點傳送一份數據報的複製。若是UDP數據報到達的是一個單播地址,那麼只向其中一個端點傳送一份數據報的複製
總結:UDP是一個簡單的協議,本文大部分篇幅都在介紹IP分片的內容,等到介紹TCP的時候,就能瞭解UDP與TCP之間的區別和聯繫