UDP:用戶數(shù)據(jù)報協(xié)議
UDP是一個簡單的面向數(shù)據(jù)報的傳輸層協(xié)議:進程的每個輸出操作都正好產(chǎn)生一個UDP數(shù)據(jù)報,并組裝成一份待發(fā)送的IP數(shù)據(jù)報。這與面向流字符的協(xié)議不同,如TCP,應用程序產(chǎn)生的全體數(shù)據(jù)與真正發(fā)送的單個IP數(shù)據(jù)報可能沒有什么聯(lián)系。
UDP數(shù)據(jù)報封裝成一份IP數(shù)據(jù)報的格式如下圖:

UTP不提供可靠性:它把應用程序傳給IP層的數(shù)據(jù)發(fā)送出去,但是并不保證它們能到達目的地。
應用程序必須注意IP數(shù)據(jù)報的長度。如果它超過網(wǎng)絡(luò)MTU(最大傳輸單元),那么就要對IP數(shù)據(jù)報進行分片。如果需要源端到目的端的每個網(wǎng)絡(luò)都要進行分片,并不只是發(fā)送端主機連接第一個網(wǎng)絡(luò)才這樣做。
UDP首部
首部結(jié)構(gòu)如下圖:

端口號表示發(fā)送進程和接受進程,由于IP層已經(jīng)把IP數(shù)據(jù)報分配給TCP或UDP(根據(jù)IP首部中協(xié)議字段值),因此TCP端口號由TCP來查看,而UDP端口號由UDP來查看。TCP端口號與UDP端口號是相互獨立的。
UDP長度字段指的是UDP首部和UDP數(shù)據(jù)的字節(jié)長度。該字段的最小值為8字節(jié)(發(fā)送一份0字節(jié)的UDP數(shù)據(jù)報是OK的)。這個UDP長度是有冗余的,IP數(shù)據(jù)報長度指的是數(shù)據(jù)報全長,因此UDP數(shù)據(jù)報長度等于IP數(shù)據(jù)報長度減去IP首部的長度。
UDP校驗和
UDP校驗和覆蓋UDP首部和UDP數(shù)據(jù)?;叵隝P首部的校驗和,它只覆蓋IP的首部----并不覆蓋IP數(shù)據(jù)報的任何數(shù)據(jù)。

UDP和TCP在首部都有覆蓋它們首部和數(shù)據(jù)的校驗和。UDP校驗和是可選的,而TCP的校驗和是必需的。
盡管U D P檢驗和的基本計算方法與我們之前第三節(jié)中描述的IP首部檢驗和計算方法相類似(16bit字的二進制反碼和),但是它們之間存在不同的地方。首先,UDP數(shù)據(jù)報的長度可以為奇數(shù)字節(jié),但是檢驗和算法是把若干個16bit字相加。解決方法是必要時在最后增加填充字節(jié)0,這只是為了檢驗和的計算(也就是說,可能增加的填充字節(jié)不被傳送)。
如果發(fā)送端沒有計算檢驗和而接收端檢測到檢驗和有差錯,那么UDP數(shù)據(jù)報就要被悄悄地丟棄。不產(chǎn)生任何差錯報文(當IP層檢測到IP首部檢驗和有差錯時也這樣做)。
UDP檢驗和是一個端到端的檢驗和。它由發(fā)送端計算,然后由接收端驗證。其目的是為了發(fā)現(xiàn)UDP首部和數(shù)據(jù)在發(fā)送端到接收端之間發(fā)生的任何改動。
分片
物理網(wǎng)絡(luò)層一般要限制每次發(fā)送數(shù)據(jù)幀的最大長度。任何時候IP層接收到一份要發(fā)送的IP數(shù)據(jù)報時,它要判斷向本地哪個接口發(fā)送數(shù)據(jù)(選路),并查詢該接口獲得其MTU。IP把MTU與數(shù)據(jù)報長度進行比較,如果需要則進行分片。分片可以發(fā)生在原始發(fā)送端主機上,也可以發(fā)生在中間路由器上。

把一份IP數(shù)據(jù)報進行分片以后,只有到達目的地才進行重新組裝(這里的重新組裝與其他網(wǎng)絡(luò)協(xié)議不同,它們要求在下一站就進行重新組裝,而不是在最終目的地)。重新組裝由目的端的IP層來完成,其目的是使分片和重新組裝過程對傳輸層(TCP和UDP)是透明的。已經(jīng)分片過得數(shù)據(jù)報可能會再次進行分片,IP首部中包含的數(shù)據(jù)為分片和重新組裝提供了足夠的信息。
對于發(fā)送端發(fā)送的每份IP數(shù)據(jù)報來說,其標識字段都包含一個唯一值。該值在數(shù)據(jù)報分片時被復制到每個片中。標志字段其中一個比特來表示"更多的片"。除了最后一片外,其他每個組成數(shù)據(jù)報的片都要把比特置1。片偏移字段指的是該片偏移原始數(shù)據(jù)報開始處的位置。另外,當數(shù)據(jù)報被分片后,每個片的總長度值要改為該片的長度值。
最后,標志字段中有一個比特稱作“不分片”位。如果將這一比特置1,IP將不對數(shù)據(jù)報進行分片。相反把數(shù)據(jù)報丟棄并發(fā)送一個ICMP差錯報(“需要進行分片但設(shè)置了不分片比特”)給起始端。
當IP數(shù)據(jù)報被分片后,每一片都成為一個分組,具有自己的IP首部,并在選擇路由時與其他分組獨立。這樣,當數(shù)據(jù)報的這些片到達目的端時可能會失序,但是在IP首部中有足夠的信息讓接收端能正確組裝這些數(shù)據(jù)報片。
IP分片有一個問題:丟失掉一片數(shù)據(jù)也要重新傳輸整個數(shù)據(jù)報。
原因:IP層沒有超時重傳機制---由更高層負責超時和重傳。當來自TCP報文段的某一片丟失后,TCP超時會重發(fā)整個TCP報文段,該報文段對應于一份IP數(shù)據(jù)報。沒有辦法重傳數(shù)據(jù)報中的一個數(shù)據(jù)報片。
使用UDP很容易導致IP分片。下圖是UDP分片示例:
ICMP不可達差錯(需要分片)
發(fā)現(xiàn)ICMP不可達差錯的另一種情況是,當路由器收到一份需要分片的數(shù)據(jù)報,而在IP首部又設(shè)置了不分片(DF)的標志比特。如果某個程序需要判斷到達目的端的路途中最小MTU是多少----稱作路徑MTU發(fā)現(xiàn)機制,那么這個差錯就可以被該程序使用。
這個情況下ICMP不可達差錯報文格式如下圖:

如果路由器沒有提供這種新的ICMP差錯報文格式,那么下一站的MTU就為0。
最大UDP數(shù)據(jù)報長度
理論上,IP數(shù)據(jù)報的最大長度是65535字節(jié),這是由IP首部16比特總長度字段所限制的。去除20字節(jié)的IP首部和8個字節(jié)的UDP首部,UDP數(shù)據(jù)報中用戶數(shù)據(jù)的最長長度為65507字節(jié)。但是,大多數(shù)實現(xiàn)所提供的長度比這個最大值小。
其中有兩個限制因素:
1.應用程序可能會受到其程序接口的限制。socket API提供了一個可供應用程序調(diào)用的函數(shù),以設(shè)置接收和發(fā)送緩存的長度。對于UDP socket,這個長度與應用程序可以讀寫的最大UDP數(shù)據(jù)報的長度直接相關(guān)。
2.第二個限制來自于TCP/IP的內(nèi)核實現(xiàn)??赡艽嬖谝恍崿F(xiàn)特性(或差錯),是IP數(shù)據(jù)報長度小于65535字節(jié)。
ICMP源站抑制差錯
我們同樣可以使用UDP纏上ICMP"源站抑制"差錯。當一個系統(tǒng)(路由器或主機)接受數(shù)據(jù)報的速度比其處理速度快時,可能產(chǎn)生這個差錯。

當在以太網(wǎng)傳播的數(shù)據(jù)需要經(jīng)過SLIP鏈路時,可能產(chǎn)生該差錯報文。因為SLIP鏈路的速度大約只有以太網(wǎng)的千分之一,所以,很容易使其緩存用完。
在本例中,應用程序要么沒有接收到源站抑制差錯信號,要么接收到卻將其忽略了。結(jié)果是如果采用UDP協(xié)議,那么BSD實現(xiàn)通常忽略其接收到的源站抑制報文。其部分原因在于,在接收到源站抑制差錯報文時,導致源站抑制的進程可能已經(jīng)中止了。
不處理ICMP源站抑制差錯,說明了UDP是一個非可靠的協(xié)議,它只控制端到端的流量控制。除非在應用程序中建立一些應答機制,否則發(fā)送端并不知道接收端是否收到了這些數(shù)據(jù)。
UDP服務器的設(shè)計
客戶IP地址以及端口號
來自客戶的是UDP數(shù)據(jù)報。IP首部包含源端和目的端IP地址,UDP首部包含了源端和目的端的UDP端口號。當一個應用程序接收到UDP數(shù)據(jù)報時,操作系統(tǒng)必須告訴它是誰發(fā)送了這份消息,即源IP地址和端口號。
這個特性允許一個交互UDP服務器對多個客戶進行處理。給每個發(fā)送請求的客戶發(fā)回應答。
目的IP地址
一些應用程序需要知道數(shù)據(jù)報是發(fā)給誰的,即目的地址。這要求操作系統(tǒng)從接收到的UDP數(shù)據(jù)報中將目的IP地址交給應用程序。
UDP輸入隊列
大多數(shù)UDP服務器是交互服務器,單個服務器進程對單個UDP端口上的所有客戶請求進行處理。
通常程序所使用的每個UDP端口都與一個有限大小的輸入隊列向聯(lián)系。這意味著,來自不同客戶的差不多同時到達的請求將有UDP自動排隊。接收到UDP數(shù)據(jù)報以其接收順序交給應用程序。
因此,由于隊列溢出導致的UDP數(shù)據(jù)報的丟失不可避免。應用程序不知道其輸入隊列什么時候會溢出,只能有UDP對超出數(shù)據(jù)報進行丟棄處理。同時,不會發(fā)揮任何消息告訴客戶其數(shù)據(jù)報被丟棄。
限制本地IP地址
大多數(shù)UDP服務器在創(chuàng)建UDP端點時都使其本地IP地址具有通配符的特點。這表明進入的UFP數(shù)據(jù)報如果其目的地為服務端端口,那么任何本地接口均可接收到它。
限制遠端IP地址
大多數(shù)系統(tǒng)允許UDP端點對遠端地址進行限制。
下面是UDP服務器本身可以創(chuàng)建的三類地址綁定:

在所有情況下,lport指的是服務器有名端口號,localIP必須是本地接口的IP地址。表中這三行的排序是UDP模塊在判斷用哪個端點接收數(shù)據(jù)報時所采用的順序。最為確定的地址(第一行)首先被匹配,最不確定的地址(最后一行IP地址帶有兩個星號)最后進行匹配。
每個端口有多個接收者
當UDP數(shù)據(jù)報到達的目的IP地址為廣播地址或多播地址,而且在目的IP地址和端口號處有多個端點時,就向每個端點傳送一份數(shù)據(jù)報的復制(端點的本地IP地址可以含有星號,它可匹配任何目的IP地址)。但是,如果UDP數(shù)據(jù)報到達的是一個單播地址,那么只向其中一個端點傳送一份數(shù)據(jù)報的復制。選擇哪個端點傳送數(shù)據(jù)取決于各個不同的系統(tǒng)實現(xiàn)。
小結(jié)
UDP是一個簡單協(xié)議。它想用戶進程提供的服務位于IP層之上,包括端口號和可選的校驗和,我們用UDP老檢查校驗和并觀察分片是如何進行的。
當系統(tǒng)接收IP數(shù)據(jù)報的速率超過這些數(shù)據(jù)報被處理的速率時,系統(tǒng)可能發(fā)送ICMP源站抑制差錯報文。使用UDP時很容易產(chǎn)生這樣的ICMP差錯。