(兩百一十)TCP/IP詳解筆記-第11章 UDP:用戶數據報協議

11.1 引言

UDP是一個簡單的面向數據報的運輸層協議:進程的每個輸出操作都正好產生一個UDP數據報,並組裝成一份待發送的IP數據報。這與面向流字符的協議不同,如TCP,應用程序產生的全體數據與真正發送的單個IP數據報可能沒有什麼聯繫。

UDP數據報封裝成一份IP數據報的格式如圖11-1所示。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-1 UDP封裝

RFC 768[Postel 1980]是UDP的正式規規範。

UDP不提供可靠性:它把應用程序傳給IP層的數據發送出去,但是並不保證它們能到達目的地。由於缺乏可靠性,我們似乎覺得要避免使用UDP而使用一種可靠協議如TCP。我們在第17章討論完TCP後將再回到這個話題,看看什麼樣的應用程序可以使用UDP。

應用程序必須關心IP數據報的長度。如果它超過網絡的MTU(2.8節),那麼就要對IP數據報進行分片。如果需要,源端到目的端之間的每個網絡都要進行分片,並不只是發送端主機連接第一個網絡才這樣做(我們在2.9節中已定義了路徑MTU的概念)。在11.5節中,我們將討論IP分片機制。

 

11.2 UDP首部

UDP首部的各字段如圖11-2所示。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-2 UDP首部

端口號表示發送進程和接收進程。在圖1-8中,我們畫出了TCP和UDP用目的端口號來分用來自IP層的數據的過程。由於IP層已經把IP數據報分配給TCP或UDP(根據IP首部中協議字段值),因此TCP端口號由TCP來查看,而UDP端口號由UDP來查看。TCP端口號與UDP端口號是相互獨立的。

UDP長度字段指的是UDP首部和UDP數據的字節長度。該字段的最小值爲8字節(發送一份0字節的UDP數據報是OK)。這個UDP長度是有冗餘的。IP數據報長度指的是數據報全長(圖3-1),因此UDP數據報長度是全長減去IP首部的長度(該值在首部長度字段中指定,如圖3-1所示)。

 

11.3 UDP檢驗和

UDP檢驗和覆蓋UDP首部和UDP數據。回想IP首部的檢驗和,它只覆蓋IP的首部—並不覆蓋IP數據報中的任何數據。

UDP和TCP在首部中都有覆蓋它們首部和數據的檢驗和。UDP的檢驗和是可選的,而TCP的檢驗和是必需的。

儘管UDP檢驗和的基本計算方法與我們在3.2節中描述的IP首部檢驗和計算方法相類似(16 bit字的二進制反碼和),但是它們之間存在不同的地方。首先,UDP數據報的長度可以爲奇數字節,但是檢驗和算法是把若干個16 bit字相加。解決方法是必要時在最後增加填充字節0,這只是爲了檢驗和的計算(也就是說,可能增加的填充字節不被傳送)。

其次,UDP數據報和TCP段都包含一個12字節長的僞首部,它是爲了計算檢驗和而設置的。僞首部包含IP首部一些字段。其目的是讓UDP兩次檢查數據是否已經正確到達目的地(例如,IP沒有接受地址不是本主機的數據報,以及IP沒有把應傳給另一高層的數據報傳給UDP)。UDP數據報中的僞首部格式如圖11-3所示。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-3 UDP檢驗和計算過程中使用的各個字段

在該圖中,我們特地舉了一個奇數長度的數據報例子,因而在計算檢驗和時需要加上填充字節。注意,UDP數據報的長度在檢驗和計算過程中出現兩次。

如果檢驗和的計算結果爲0,則存入的值爲全1(65535),這在二進制反碼計算中是等效的。如果傳送的檢驗和爲0,說明發送端沒有計算檢驗和。

如果發送端沒有計算檢驗和而接收端檢測到檢驗和有差錯,那麼UDP數據報就要被悄悄地丟棄。不產生任何差錯報文(當IP層檢測到IP首部檢驗和有差錯時也這樣做)。

UDP檢驗和是一個端到端的檢驗和。它由發送端計算,然後由接收端驗證。其目的是爲了發現UDP首部和數據在發送端到接收端之間發生的任何改動。

儘管UDP檢驗和是可選的,但是它們應該總是在用。在80年代,一些計算機產商在默認條件下關閉UDP檢驗和的功能,以提高使用UDP協議的NFS(Network File System)的速度。在單個局域網中這可能是可以接受的,但是在數據報通過路由器時,通過對鏈路層數據幀進行循環冗餘檢驗(如以太網或令牌環數據幀)可以檢測到大多數的差錯,導致傳輸失敗。不管相信與否,路由器中也存在軟件和硬件差錯,以致於修改數據報中的數據。如果關閉端到端的UDP檢驗和功能,那麼這些差錯在UDP數據報中就不能被檢測出來。另外,一些數據鏈路層協議(如SLIP)沒有任何形式的數據鏈路檢驗和。

Host Requirements RFC 聲明,UDP檢驗和選項在默認條件下是打開的。它還聲明,如果發送端已經計算了檢驗和,那麼接收端必須檢驗接收到的檢驗和(如接收到檢驗和不爲0)。但是,許多系統沒有遵守這一點,只是在出口檢驗和選項被打開時才驗證接收到的檢驗和。

貼一下3.2 ip 的校驗和計算

“爲了計算一份數據報的IP檢驗和,首先把檢驗和字段置爲0。然後,對首部中每個16 bit進行二進制反碼求和(整個首部看成是由一串16 bit的字組成),結果存在檢驗和字段中。當收到一份IP數據報後,同樣對首部中每個16 bit進行二進制反碼的求和。由於接收方在計算過程中包含了發送方存在首部中的檢驗和,因此,如果首部在傳輸過程中沒有發生任何差錯,那麼接收方計算的結果應該爲全1。如果結果不是全1(即檢驗和錯誤),那麼IP就丟棄收到的數據報。但是不生成差錯報文,由上層去發現丟失的數據報並進行重傳。”

 

11.5 IP分片

正如我們在2.8節描述的那樣,物理網絡層一般要限制每次發送數據幀的最大長度。任何時候IP層接收到一份要發送的IP數據報時,它要判斷向本地哪個接口發送數據(選路),並查詢該接口獲得其MTU。IP把MTU與數據報長度進行比較,如果需要則進行分片。分片可以發生在原始發送端主機上,也可以發生在中間路由器上。

把一份IP數據報分片以後,只有到達目的地才進行重新組裝(這裏的重新組裝與其他網絡協議不同,它們要求在下一站就進行進行重新組裝,而不是在最終的目的地)。重新組裝由目的端的IP層來完成,其目的是使分片和重新組裝過程對運輸層(TCP和UDP)是透明的,除了某些可能的越級操作外。已經分片過的數據報有可能會再次進行分片(可能不止一次)。IP首部中包含的數據爲分片和重新組裝提供了足夠的信息。

回憶IP首部(圖3-1),下面這些字段用於分片過程。對於發送端發送的每份IP數據報來說,其標識字段都包含一個唯一值。該值在數據報分片時被複制到每個片中(我們現在已經看到這個字段的用途)。標誌字段用其中一個比特來表示“更多的片”。除了最後一片外,其他每個組成數據報的片都要把該比特置1。片偏移字段指的是該片偏移原始數據報開始處的位置。另外,當數據報被分片後,每個片的總長度值要改爲該片的長度值。

最後,標誌字段中有一個比特稱作“不分片”位。如果將這一比特置1,IP將不對數據報進行分片。相反把數據報丟棄併發送一個ICMP差錯報文(“需要進行分片但設置了不分片比特”,見圖6-3)給起始端。在下一節我們將看到出現這個差錯的例子。

當IP數據報被分片後,每一片都成爲一個分組,具有自己的IP首部,並在選擇路由時與其他分組獨立。這樣,當數據報的這些片到達目的端時有可能會失序,但是在IP首部中有足夠的信息讓接收端能正確組裝這些數據報片。

儘管IP分片過程看起來是透明的,但有一點讓人不想使用它:即使只丟失一片數據也要重傳整個數據報。爲什麼會發生這種情況呢?因爲IP層本身沒有超時重傳的機制——由更高層來負責超時和重傳(TCP有超時和重傳機制,但UDP沒有。一些UDP應用程序本身也執行超時和重傳)。當來自TCP報文段的某一片丟失後,TCP在超時後會重發整個TCP報文段,該報文段對應於一份IP數據報。沒有辦法只重傳數據報中的一個數據報片。事實上,如果對數據報分片的是中間路由器,而不是起始端系統,那麼起始端系統就無法知道數據報是如何被分片的。就這個原因,經常要避免分片。文獻[Kent and Mogul 1987]對避免分片進行了論述。

使用UDP很容易導致IP分片(在後面我們將看到,TCP試圖避免分片,但對於應用程序來說幾乎不可能強迫TCP發送一個需要進行分片的長報文段)。我們可以用sock程序來增加數據報的長度,直到分片發生。在一個以太網上,數據幀的最大長度是1500字節(見圖2-1),其中1472字節留給數據,假定IP首部爲20字節,UDP首部爲8字節。我們分別以數據長度爲1471,1472,1473和1474字節運行sock程序。最後兩次應該發生分片:

bsdi % sock -u -i -nl -w1471 svr4 discard

bsdi % sock -u -i -nl -w1472 svr4 discard

bsdi % sock -u -i -nl -w1473 svr4 discard

bsdi % sock -u -i -nl -w1474 svr4 discard

相應的tcpdump輸出如圖11-7所示。

第11章 UDP:用戶數據報協議_即時通訊網(52im.net)

圖11-7 觀察UDP數據報分片

前兩份UDP數據報(第1行和第2行)能裝入以太網數據幀,沒有被分片。但是對應於寫1473字節的IP數據報長度爲1501,就必須進行分片(第3行和第4行)。同理,寫1474字節產生的數據報長度爲1502,它也需要進行分片(第5行和第6行)。

當IP數據報被分片後,tcpdump打印出其他的信息。首先,frag26304(第3行和第4行)和frag26313(第5行和第6行)指的是IP首部中標識字段的值。

分片信息中的下一個數字,即第3行中位於冒號和@號之間的1480,是除IP首部外的片長。兩份數據報第一片的長度均爲1480:UDP首部佔8字節,用戶數據佔1472字節(加上IP首部的20字節分組長度正好爲1500字節)。第1份數據報的第2片(第4行)只包含1字節數據—剩下的用戶數據。第2份數據報的第2片(第6行)包含剩下的2字節用戶數據。

在分片時,除最後一片外,其他每一片中的數據部分(除IP首部外的其餘部分)必須是8字節的整數倍。在本例中,1480是8的整數倍。

位於@符號後的數字是從數據報開始處計算的片偏移值。兩份數據報第1片的偏移值均爲0(第3行和第5行),第2片的偏移值爲1480(第4行和第6行)。跟在偏移值後面的加號對應於IP首部中3bit標誌字段中的“更多片”比特。設置這一比特的目的是讓接收端知道在什麼時候完成所有的分片組裝。

最後,注意第4行和第6行(不是第1片)省略了協議名(UDP)、源端口號和目的端口號。協議名是可以打印出來的,因爲它在IP首部並被複制到各個片中。但是,端口號在UDP首部,只能在第1片中被發現。

發送的第3份數據報(用戶數據爲1473字節)分片情況如圖11-8所示。需要重申的是,任何運輸層首部只出現在第1片數據中。

另外需要解釋幾個術語:IP數據報是指IP層端到端的傳輸單元(在分片之前和重新組裝之後),分組是指在IP層和鏈路層之間傳送的數據單元。一個分組可以是一個完整的IP數據報,也可以是IP數據報的一個分片。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-8 UDP分片舉例

 

11.6 ICMP不可達差錯(需要分片)

發生ICMP不可達差錯的另一種情況是,當路由器收到一份需要分片的數據報,而在IP首部又設置了不分片(DF)的標誌比特。如果某個程序需要判斷到達目的端的路途中最小MTU是多少—稱作路徑MTU發現機制(2.9節),那麼這個差錯就可以被該程序使用。

這種情況下的ICMP不可達差錯報文格式如圖11-9所示。這裏的格式與圖6-10不同,因爲在第2個32 bit字中,16~31 bit可以提供下一站的MTU,而不再是0。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-9 需要分片但又設置不分片標誌比特時的ICMP不可達差錯報文格式

如果路由器沒有提供這種新的ICMP差錯報文格式,那麼下一站的MTU就設爲0。

 

11.7 用Traceroute確定路徑MTU

儘管大多數的系統不支持路徑MTU發現功能,但可以很容易地修改traceroute程序(第8章),用它來確定路徑MTU。要做的是發送分組,並設置“不分片”標誌比特。發送的第一個分組的長度正好與出口MTU相等,每次收到ICMP“不能分片”差錯時(在上一節討論的)就減小分組的長度。如果路由器發送的ICMP差錯報文是新格式,包含出口的MTU,那麼就用該MTU值來發送,否則就用下一個最小的MTU值來發送。正如RFC 1191[Mogul and Deering 1990]聲明的那樣,MTU值的個數是有限的,因此在我們的程序中有一些由近似值構成的表,取下一個最小MTU值來發送。

首先,我們嘗試判斷從主機sun到主機slip的路徑MTU,知道SLIP鏈路的MTU爲296。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

在這個例子中,路由器bsdi沒有在ICMP差錯報文中返回出口MTU,因此我們選擇另一個MTU近似值。TTL爲2的第1行輸出打印的主機名爲bsdi,但這是因爲它是返回ICMP差錯報文的路由器。TTL爲2的最後一行正是我們所要找的。

在bsdi上修改ICMP代碼使它返回出口MTU值並不困難,如果那樣做並再次運行該程序,得到如下輸出結果:

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

這時,在找到正確的MTU值之前,我們不用逐個嘗試8個不同的MTU值——路由器返回了正確的MTU值。

 

11.8 採用UDP的路徑MTU發現

下面對使用UDP的應用程序與路徑MTU發現機制之間的交互作用進行研究。看一看如果應用程序寫了一個對於一些中間鏈路來說太長的數據報時會發生什麼情況。

例子

由於我們所使用的支持路徑MTU發現機制的唯一系統就是Solaris 2.x,因此,將採用它作爲源站發送一份650字節數據報經slip。由於slip主機位於MTU爲296的SLIP鏈路後,因此,任何長於268字節(296-20-8)且“不分片”比特置爲1的UDP數據都會使bsdi路由器產生ICMP“不能分片”差錯報文。圖11-13給出了拓撲結構和MTU。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-13 使用UDP進行路徑MTU發現的系統

可以用下面的命令行來產生650字節UDP數據報,每兩個UDP數據報之間的間隔是5秒:

solaris %sock -u -i -n10 -w650 -p5 slip discard

圖11-14是tcpdump的輸出結果。在運行這個例子時,將bsdi設置成在ICMP“不能分片”差錯中,不返回下一跳MTU信息。

在發送的第一個數據報中將DF比特置1(第1行),其結果是從bsdi路由器發回我們可以猜測的結果(第2行)。令人不解的是,發送一個DF比特置1的數據報(第3行),其結果是同樣的ICMP差錯(第4行)。我們預計這個數據報在發送時應該將DF比特置0。

第5行結果顯示,IP已經知道了發往該目的地址的數據報不能將DF比特置1,因此,IP進而將數據報在源站主機上進行分片。這與前面的例子中,IP發送經過UDP的數據報,允許具有較小MTU的路由器(在本例中是bsdi)對它進行分片的情況不一樣。由於ICMP“不能分片”報文並沒有指出下一跳的MTU,因此,看來IP猜測MTU爲576就行了。第一次分片(第5行)包含544字節的UDP數據、8字節UDP首部以及20字節IP首部,因此,總IP數據報長度是572字節。第2次分片(第6行)包含剩餘的106字節UDP數據和20字節IP首部。

不幸的是,第7行的下一個數據報將其DF比特置1,因此bsdi將它丟棄並返回ICMP差錯。這時發生了IP定時器超時,通知IP查看是不是因爲路徑MTU增大了而將DF比特再一次置1。我們可以從第19行和20行看出這個結果。將第7行與19行進行比較,可以看出IP每過30秒就將DF比特置1,以查看路徑MTU是否增大了。

這個30秒的定時器值看來太短。RFC11 91建議其值取10分鐘。可以通過修改ip_ire_pathmtu_interval(E.4節)參數來改變該值。同時,Solaris 2.2無法對單個UDP應用或所有UDP應用關閉該路徑MTU發現。只能通過修改ip_path_mtu_discovery參數,在系統一級開放或關閉它。正如在這個例子裏所能看到的那樣,如果允許路徑MTU發現,那麼當UDP應用程序寫入可能被分片數據報時,該數據報將被丟棄。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-14 使用UDP路徑MTU發現

solaris的IP層所假設的最大數據報長度(576字節)是不正確的。在圖11-13中,我們看到,實際的MTU值是296字節。這意味着經solaris分片的數據報還將被bsdi分片。圖11-15給出了在目的主機(slip)上所收集到的tcpdump對於第一個到達數據報的輸出結果(圖11-14的第5行和第6行)。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-15 從solaris到達slip的第一個數據報

在本例中,solaris不應該對外出數據報分片,它應該將DF比特置0,讓具有最小MTU的路由器來完成分片工作。

現在我們運行同一個例子,只是對路由器bsdi進行修改使其在ICMP“不能分片”差錯中返回下一跳MTU。圖11-16給出了tcpdump輸出結果的前6行。

與圖11-14一樣,前兩個數據報同樣是將DF比特置1後發送出去的。但是在知道了下一跳MTU後,只產生了3個數據報片,而圖11-15中的bsdi路由器則產生了4個數據報片。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-16 使用UDP的路徑MTU發現

 

11.9 UDP和ARP之間的交互作用

使用UDP,可以看到UDP與ARP典型實現之間的有趣的(而常常未被人提及)交互作用。

我們用sock程序來產生一個包含8192字節數據的UDP數據報。預測這將會在以太網上產生6個數據報片(見習題11.3)。同時也確保在運行該程序前,ARP緩存是清空的,這樣,在發送第一個數據報片前必須交換ARP請求和應答。

bsdi % arp -a         驗證ARP高速緩存是空的

bsdi % sock -u -i -nl -w8192 svr4 discard

預計在發送第一個數據報片前會先發送一個ARP請求。IP還會產生5個數據報片,這樣就提出了我們必須用tcpdump來回答的兩個問題:在接收到ARP回答前,其餘數據報片是否已經做好了發送準備?如果是這樣,那麼在ARP等待應答時,它會如何處理髮往給定目的的多個報文?圖11-17給出了tcpdump的輸出結果。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-17 在以太網上發送8192字節UDP數據報時的報文交換

在這個輸出結果中有一些令人吃驚的結果。首先,在第一個ARP應答返回以前,總共產生了6個ARP請求。我們認爲其原因是IP很快地產生了6個數據報片,而每個數據報片都引發了一個ARP請求。

第二,在接收到第一個ARP應答時(第7行),只發送最後一個數據報片(第9行)!看來似乎將前5個數據報片全都丟棄了。實際上,這是ARP的正常操作。在大多數的實現中,在等待一個ARP應答時,只將最後一個報文發送給特定目的主機。

Host Requirements RFC要求實現中必須防止這種類型的ARP洪泛(ARP flooding,即以高速率重複發送到同一個IP地址的ARP請求)。建議最高速率是每秒一次。而這裏卻在4.3ms內發出了6個ARP請求。

另一個無法解釋的不正常的現象是,svr4發回7個,而不是6個ARP應答。

最後要指出的是,在最後一個ARP應答返回後,繼續運行tcpdump程序5分鐘,以看看svr4是否會返回ICMP“組裝超時”差錯。並沒有發送ICMP差錯(我們在圖8-2中給出了該消息的格式。code字段爲1表示在重新組裝數據報時發生了超時)。

在第一個數據報片出現時,IP層必須啓動一個定時器。這裏“第一個”表示給定數據報的第一個到達數據報片,而不是第一個數據報片(數據報片偏移爲0)。正常的定時器值爲30或60秒。如果定時器超時而該數據報的所有數據報片未能全部到達,那麼將這些數據報片丟棄。如果不這麼做,那些永遠不會到達的數據報片(正如我們在本例中所看到的那樣)遲早會引起接收端緩存滿。

這裏我們沒看到ICMP消息的原因有兩個。首先,大多數從Berkeley派生的實現從不產生該差錯!這些實現會設置定時器,也會在定時器溢出時將數據報片丟棄,但是不生成ICMP差錯。第二,並未接收到包含UDP首部的偏移量爲0的第一個數據報片(這是被ARP所丟棄的5個報文的第1個)。除非接收到第一個數據報片,否則並不要求任何實現產生ICMP差錯。其原因是因爲沒有運輸層首部,ICMP差錯的接收者無法區分出是哪個進程所發送的數據報被丟棄。這裏假設上層(TCP或使用UDP的應用程序)最終會超時並重傳。

在本節中,我們使用IP數據報片來查看UDP與ARP之間的交互作用。如果發送端迅速發送多個UDP數據報,也可以看到這個交互過程。我們選擇採用分片的方法,是因爲IP可以生成報文的速度,比一個用戶進程生成多個數據報的速度更快。

儘管本例看來不太可能,但它確實經常發生。NFS發送的UDP數據報長度超過8192字節。在以太網上,這些數據報以我們所指出的方式進行分片,如果適當的ARP緩存入口發生超時,那麼就可以看到這裏所顯示的現象。NFS將超時並重傳,但是由於ARP的有限隊列,第一個IP數據報仍可能被丟棄。

 

11.10 最大UDP數據報長度

理論上,IP數據報的最大長度是65535字節,這是由IP首部(圖3-1)16比特總長度字段所限制的。去除20字節的IP首部和8個字節的UDP首部,UDP數據報中用戶數據的最長長度爲65507字節。但是,大多數實現所提供的長度比這個最大值小。

我們將遇到兩個限制因素。第一,應用程序可能會受到其程序接口的限制。socket API提供了一個可供應用程序調用的函數,以設置接收和發送緩存的長度。對於UDP socket,這個長度與應用程序可以讀寫的最大UDP數據報的長度直接相關。現在的大部分系統都默認提供了可讀寫大於8192字節的UDP數據報(使用這個默認值是因爲8192是NFS讀寫用戶數據數的默認值)。

第二個限制來自於TCP/IP的內核實現。可能存在一些實現特性(或差錯),使IP數據報長度小於65535字節。

我們在3.2節中提過,要求主機必須能夠接收最短爲576字節的IP數據報。在許多UDP應用程序的設計中,其應用程序數據被限制成512字節或更小,因此比這個限制值小。例如,我們在10.4節中看到,路徑信息協議總是發送每份數據報小於512字節的數據。我們還會在其他UDP應用程序如DNS(第14章)、TFTP(第15章)、BOOTP(第16章)以及SNMP(第25章)中遇到這個限制。

數據報截斷

由於IP能夠發送或接收特定長度的數據報並不意味着接收應用程序可以讀取該長度的數據。因此,UDP編程接口允許應用程序指定每次返回的最大字節數。如果接收到的數據報長度大於應用程序所能處理的長度,那麼會發生什麼情況呢?

不幸的是,該問題的答案取決於編程接口和實現。

典型的Berkeley版socket API對數據報進行截斷,並丟棄任何多餘的數據。應用程序何時能夠知道,則與版本有關(4.3BSD Reno及其後的版本可以通知應用程序數據報被截斷)。

SVR4下的socket API(包括Solaris 2.x)並不截斷數據報。超出部分數據在後面的讀取中返回。它也不通知應用程序從單個UDP數據報中多次進行讀取操作。

TLI API不丟棄數據。相反,它返回一個標誌表明可以獲得更多的數據,而應用程序後面的讀操作將返回數據報的其餘部分。

在討論TCP時,我們發現它爲應用程序提供連續的字節流,而沒有任何信息邊界。TCP以應用程序讀操作時所要求的長度來傳送數據,因此,在這個接口下,不會發生數據丟失。

 

11.11 ICMP源站抑制差錯

我們同樣也可以使用UDP產生ICMP“源站抑制(source quench)”差錯。當一個系統(路由器或主機)接收數據報的速度比其處理速度快時,可能產生這個差錯。注意限定詞“可能”。即使一個系統已經沒有緩存並丟棄數據報,也不要求它一定要發送源站抑制報文。

圖11-18給出了ICMP源站抑制差錯報文的格式。有一個很好的方案可以在我們的測試網絡裏產生該差錯報文。可以從bsdi通過必須經過撥號SLIP鏈路的以太網,將數據報發送給路由器sun。由於SLIP鏈路的速度大約只有以太網的千分之一,因此,我們很容易就可以使其緩存用完。下面的命令行從主機bsdi通過路由器sun發送100個1024字節長數據報給solaris。我們將數據報發送給標準的丟棄服務,這樣,這些數據報將被忽略:

bsdi % sock -u -i -w1024 -n100 solaris discard

圖11-19給出了與此命令行相對應的tcpdump輸出結果。

在這個輸出結果中,刪除了很多行,這只是一個模型。接收前26個數據報時未發生差錯;我們只給出了第一個數據報的結果。然而,從第27個數據報開始,每發送一份數據報,就會接收到一份源站抑制差錯報文。總共有26+(74×2)=174行輸出結果。

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-18 ICMP源站抑制差錯報文格式

第11章 UDP:用戶數據報協議_TCP/IP詳解卷1 協議_即時通訊網(52im.net)

圖11-19 來自路由器sun的ICMP源站抑制

從2.10節的並行線吞吐率計算結果可以知道,以9600 b/s速率傳送1024字節數據報只需要1秒時間(由於從sun到netb的SLIP鏈路的MTU爲552字節,因此在我們的例子中,20+8+1024字節數據報將進行分片,因此,其時間會稍長一些)。但是我們可以從圖11-19的時間中看出,sun路由器在不到1秒時間內就處理完所有的100個數據報,而這時,第一份數據報還未通過SLIP鏈路。因此我們用完其緩存就不足不奇了。

儘管RFC 1009 [Braden and Postel 1987]要求路由器在沒有緩存時產生源站抑制差錯報文,但是新的Router Requirements RFC [Almquist 1993]對此作了修改,提出路由器不應該產生源站抑制差錯報文。由於源站抑制要消耗網絡帶寬,且對於擁塞來說是一種無效而不公平的調整,因此現在人們對於源站抑制差錯的態度是不支持的。

在本例中,還需要指出的是,sock程序要麼沒有接收到源站抑制差錯報文,要麼接收到卻將它們忽略了。結果是如果採用UDP協議,那麼BSD實現通常忽略其接收到的源站抑制報文(正如我們在21.10節所討論的那樣,TCP接受源站抑制差錯報文,並將放慢在該連接上的數據傳輸速度)。其部分原因在於,在接收到源站抑制差錯報文時,導致源站抑制的進程可能已經中止了。實際上,如果使用Unix的time程序來測定sock程序所運行的時間,其結果是它只運行了大約0.5秒時間。但是從圖11-19中可以看到,在發送第一份數據報過後0.71秒才接收到一些源站抑制,而此時該進程已經中止。其原因是我們的程序寫入了100個數據報然後中止了。但是所有的100個數據報都已發送出去—有一些數據報在輸出隊列中。

這個例子重申了UDP是一個非可靠的協議,它說明了端到端的流量控制。儘管sock程序成功地將100個數據報寫入其網絡,但只有26個數據報真正發送到了目的端。其他74個數據報可能被中間路由器丟棄。除非在應用程序中建立一些應答機制,否則發送端並不知道接收端是否收到了這些數據。

 

11.12 UDP服務器的設計

使用UDP的一些蘊含對於設計和實現服務器會產生影響。通常,客戶端的設計和實現比服務器端的要容易一些,這就是我們爲什麼要討論服務器的設計,而不是討論客戶端的設計的原因。典型的服務器與操作系統進行交互作用,而且大多數需要同時處理多個客戶。

通常一個客戶啓動後直接與單個服務器通信,然後就結束了。而對於服務器來說,它啓動後處於休眠狀態,等待客戶請求的到來。對於UDP來說,當客戶數據報到達時,服務器甦醒過來,數據報中可能包含來自客戶的某種形式的請求消息。

在這裏我們所感興趣的並不是客戶和服務器的編程方面([Stevens 1990]對這些方面的細節進行了討論),而是UDP那些影響使用該協議的服務器的設計和實現方面的協議特性(我們在18.11節中對TCP服務器的設計進行了描述)。儘管我們所描述的一些特性取決於所使用UDP的實現,但對於大多數實現來說,這些特性是公共的。

 

11.13 小結

UDP是一個簡單協議。它的正式規範是RFC 768 [Postel 1980],只包含三頁內容。它向用戶進程提供的服務位於IP層之上,包括端口號和可選的檢驗和。我們用UDP來檢查檢驗和,並觀察分片是如何進行的。

接着,我們討論了ICMP不可達差錯,它是新的路徑MTU發現功能中的一部分(2.9節)。用Tr aceroute和UDP來觀察路徑MTU發現過程。還查看了UDP和ARP之間的接口,大多數的ARP實現在等待ARP應答時只保留最近傳送給目的端的數據報。

當系統接收IP數據報的速率超過這些數據報被處理的速率時,系統可能發送ICMP源站抑制差錯報文。使用UDP時很容易產生這樣的ICMP差錯。

 

 

 

 

 

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