1. 程式人生 > >為什麼udp為什麼不能傳送大於1472位元組資料

為什麼udp為什麼不能傳送大於1472位元組資料

在進行UDP程式設計的時候,我們最容易想到的問題就是,一次傳送多少bytes好?

       當然,這個沒有唯一答案,相對於不同的系統,不同的要求,其得到的答案是不一樣的,這裡僅對像ICQ一類的傳送聊天訊息的情況作分析,對於其他情況,或許也能得到一點幫助: 
首先,我們知道,TCP/IP通常被認為是一個四層協議系統,包括鏈路層,網路層,傳輸層,應用層.UDP屬於運輸層,下面我們由下至上一步一步來看: 
乙太網(Ethernet)資料幀的長度必須在46-1500位元組之間,這是由乙太網的物理特性決定的.這個1500位元組被稱為鏈路層的MTU(最大傳輸單元).但這並不是指鏈路層的長度被限制在1500位元組,其實這個MTU指的是鏈路層的資料區.並不包括鏈路層的首部和尾部的18個位元組.所以,事實上,這個1500位元組就是網路層IP資料報的長度限制.因為IP資料報的首部為20位元組,所以IP資料報的資料區長度最大為1480位元組.而這個1480位元組就是用來放TCP傳來的TCP報文段或UDP傳來的UDP資料報的.又因為UDP資料報的首部8位元組,所以UDP資料報的資料區最大長度為1472位元組.這個1472位元組就是我們可以使用的位元組數。:) 
當我們傳送的UDP資料大於1472的時候會怎樣呢?這也就是說IP資料報大於1500位元組,大於 MTU.這個時候傳送方IP層就需要分片(fragmentation).把資料報分成若干片,使每一片都小於MTU.而接收方IP層則需要進行資料報的重組.這樣就會多做許多事情,而更嚴重的是,由於UDP的特性,當某一片資料傳送中丟失時,接收方便無法重組資料報.將導致丟棄整個UDP資料報。 
因此,在普通的區域網環境下,我建議將UDP的資料控制在1472位元組以下為好. 
進行Internet程式設計時則不同,因為Internet上的路由器可能會將MTU設為不同的值.如果我們假定MTU為1500來發送資料的,而途經的某個網路的MTU值小於1500位元組,那麼系統將會使用一系列的機制來調整MTU值,使資料報能夠順利到達目的地,這樣就會做許多不必要的操作.鑑於 Internet上的標準MTU值為576位元組,所以我建議在進行Internet的UDP程式設計時.最好將UDP的資料長度控制元件在548位元組 (576-8-20)以內.

理論上,IP資料報的最大長度是65535位元組,這是由IP首部16位元總長度欄位所限制的。去除20位元組的IP首部和8個位元組的UDP首部,UDP資料報中使用者資料的最長長度為65507位元組。但是,大多數實現所提供的長度比這個最大值小。 
我們將遇到兩個限制因素。第一,應用程式可能會受到其程式介面的限制。socket API提供了一個可供應用程式呼叫的函式,以設定接收和傳送快取的長度。對於UDP socket,這個長度與應用程式可以讀寫的最大UDP資料報的長度直接相關。現在的大部分系統都預設提供了可讀寫大於8192位元組的UDP資料報(使用這個預設值是因為8192是NFS讀寫使用者資料數的預設值)。 
第二個限制來自於TCP/IP的核心實現。可能存在一些實現特性(或差錯),使IP資料報長度小於65535位元組。 
在SunOS 4.1.3下使用環回介面的最大IP資料報長度是32767位元組。比它大的值都會發生差錯。 
但是從BSD/386到SunOS 4.1.3的情況下,Sun所能接收到最大IP資料報長度為32786位元組(即32758位元組使用者資料)。 
在Solaris 2.2下使用環回介面,最大可收發IP資料報長度為65535位元組。 
從Solaris 2.2到AIX 3.2.2,傳送的最大IP資料報長度可以是65535位元組。很顯然,這個限制與源端和目的端的實現有關。 
主機必須能夠接收最短為576位元組的IP資料報。在許多UDP應用程式的設計中,其應用程式資料被限制成512位元組或更小,因此比這個限制值小。 
由於IP能夠傳送或接收特定長度的資料報並不意味著接收應用程式可以讀取該長度的資料。因此,UDP程式設計介面允許應用程式指定每次返回的最大位元組數。如果接收到的資料報長度大於應用程式所能處理的長度,那麼會發生什麼情況呢?不幸的是,該問題的答案取決於程式設計介面和實現。 
典型的Berkeley版socket API對資料報進行截斷,並丟棄任何多餘的資料。應用程式何時能夠知道,則與版本有關(4.3BSD Reno及其後的版本可以通知應用程式資料報被截斷)。 
SVR4 下的socket API(包括Solaris 2.x) 並不截斷資料報。超出部分資料在後面的讀取中返回。它也不通知應用程式從單個UDP資料報中多次進行讀取操作。TLI API不丟棄資料。相反,它返回一個標誌表明可以獲得更多的資料,而應用程式後面的讀操作將返回資料報的其餘部分。在討論TCP時,我們發現它為應用程式提供連續的位元組流,而沒有任何資訊邊界。TCP以應用程式讀操作時所要求的長度來傳送資料,因此,在這個介面下,不會發生資料丟失。

 

----------------------------------------------------------------------------------------------------------------------------------------------------
****************************************************************************************************************************************************
TCP 和 UDP 協議傳送資料包的大小(淺析)


MTU最大傳輸單元,這個最大傳輸單元實際上和鏈路層協議有著密切的關係,EthernetII幀的結構DMAC+SMAC+Type+Data+CRC由於乙太網傳輸電氣方面的限制,每個乙太網幀都有最小的大小64bytes最大不能超過1518bytes,對於小於或者大於這個限制的乙太網幀我們都可以視之為錯誤的資料幀,一般的乙太網轉發裝置會丟棄這些資料幀。 


由於乙太網EthernetII最大的資料幀是1518Bytes這樣,刨去乙太網幀的幀頭(DMAC目的MAC地址48bit=6Bytes+SMAC源MAC地址48bit=6Bytes+Type域2bytes)14Bytes和幀尾CRC校驗部分4Bytes那麼剩下承載上層協議的地方也就是Data域最大就只能有1500Bytes這個值我們就把它稱之為MTU。 

PPPoE所謂PPPoE就是在乙太網上面跑PPP協議,有人奇怪了,PPP協議和Ethernet不都是鏈路層協議嗎?怎麼一個鏈路層跑到另外一個鏈路層上面去了,難道升級成網路層協議了不成。其實這是個誤區:就是某層協議只能承載更上一層協議。 

為什麼會產生這種奇怪的需求呢?這是因為隨著寬頻接入(這種寬頻接入一般為Cable Modem或者xDSL或者乙太網的接入),因為乙太網缺乏認證計費機制而傳統運營商是通過PPP協議來對撥號等接入服務進行認證計費的. 

PPPoE帶來了好處,也帶來了一些壞處,比如:二次封裝耗費資源,降低了傳輸效能等等,這些壞處俺也不多說了,最大的壞處就是PPPoE導致MTU變小了乙太網的MTU是1500,再減去PPP的包頭包尾的開銷(8Bytes),就變成1492。 

UDP 包的大小就應該是 1492 - IP頭(20) - UDP頭(8) = 1464(BYTES) 
TCP 包的大小就應該是 1492 - IP頭(20) - TCP頭(20) = 1452(BYTES) 

目前大多數的路由裝置的MTU都為1500 
我對上面的理解是:如果我們定義的TCP和UDP包小於1452,1464,那麼我們的包在IP層就不用分包了,這樣傳輸過程中就避免了在IP層組包發生的錯誤。如果使用UDP協議,如果IP層組包發生錯誤,那麼包就會被丟棄,UDP不保證可靠傳輸。但是TCP發生組包錯誤時,該包會被重傳,保證可靠傳輸。所以,我們在用Socket程式設計時,包的大小設定不一定非要小於1400,UDP協議要求包小於64K,TCP沒有限定。 




總結:

我們設定包的大小對於UDP和TCP協議是不同的,關鍵是看系統性能和網路效能,網路是狀態很好的區域網,那麼UDP包分大點,提高系統的效能。不好,就分小於1464,這樣可以減低丟包率。對於TCP來說,這個就要靠經驗了,因為,TCP丟包可以自動重傳,分大了,系統性能提高了,分包和錯誤重組可能會耗費時間,使傳送時間延長,分小了,系統性能又降低了。