UDP丟包原因

來源:互聯網
上載者:User
(轉載自http://www.cnblogs.com/mengyan/archive/2012/10/04/2711340.html)學習之

一、主要丟包原因

1、接收端處理時間過長導致丟包:調用recv方法接收端收到資料後,處理資料花了一些時間,處理完後再次調用recv方法,在這二次調用間隔裡,發過來的包可能丟失。對於這種情況可以修改接收端,將包接收後存入一個緩衝區,然後迅速返回繼續recv。

2、發送的包巨大丟包:雖然send方法會幫你做大包切割成小包發送的事情,但包太大也不行。例如超過50K的一個udp包,不切割直接通過send方法發送也會導致這個包丟失。這種情況需要切割成小包再逐個send。

3、發送的包較大,超過接受者緩衝導致丟包:包超過mtu size數倍,幾個大的udp包可能會超過接收者的緩衝,導致丟包。這種情況可以設定socket接收緩衝。以前遇到過這種問題,我把接收緩衝設定成64K就解決了。
int nRecvBuf=32*1024;//設定為32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));

具體設定代碼可以參考下面連結:
http://blog.sina.com.cn/s/blog_a459dcf5010153mp.html

4、發送的包頻率太快:雖然每個包的大小都小於mtu
size 但是頻率太快,例如40多個mut size的包連續發送中間不sleep,也有可能導致丟包。這種情況也有時可以通過設定socket接收緩衝解決,但有時解決不了。所以在發送頻率過快的時候還是考慮sleep一下吧。

5、區域網路內不丟包,公網上丟包。這個問題我也是通過切割小包並sleep發送解決的。如果流量太大,這個辦法也不靈了。總之udp丟包總是會有的,如果出現了用我的方法解決不了,還有這個幾個方法:要麼減小流量,要麼換tcp協議傳輸,要麼做丟包重傳的工作。

二、具體問題分析

1.發送頻率過高導致丟包

很多人會不理解發送速度過快為什麼會產生丟包,原因就是UDP的SendTo不會造成線程阻塞,也就是說,UDP的SentTo不會像TCP中的SendTo那樣,直到資料完全發送才會return回調用函數,它不保證當執行下一條語句時資料是否被發送。(SendTo方法是非同步)這樣,如果要發送的資料過多或者過大,那麼在緩衝區滿的那個瞬間要發送的報文就很有可能被丟失。至於對“過快”的解釋,作者這樣說:“A
few packets a second are not an issue; hundreds or thousands may be an issue.”(一秒鐘幾個資料包不算什麼,但是一秒鐘成百上千的資料包就不好辦了)。 要解決接收方丟包的問題很簡單,首先要保證程式執行後馬上開始監聽(如果資料包不確定什麼時候發過來的話),其次,要在收到一個資料包後最短的時間內重新回到監聽狀態,其間要盡量避免複雜的操作(比較好的解決辦法是使用多線程回調機制)。

2.報文過大丟包

至於報文過大的問題,可以通過控制報文大小來解決,使得每個報文的長度小於MTU。乙太網路的MTU通常是1500 bytes,其他一些諸如撥號連線的網路MTU值為1280 bytes,如果使用speaking這樣很難得到MTU的網路,那麼最好將報文長度控制在1280 bytes以下。

3.發送方丟包

發送方丟包:內部緩衝區(internal buffers)已滿,並且發送速度過快(即發送兩個報文之間的間隔過短);  接收方丟包:Socket未開始監聽;  雖然UDP的報文長度最大可以達到64 kb,但是當報文過大時,穩定性會大大減弱。這是因為當報文過大時會被分割,使得每個分割塊(翻譯可能有誤差,原文是fragmentation)的長度小於MTU,然後分別發送,並在接收方重新組合(reassemble),但是如果其中一個報文丟失,那麼其他已收到的報文都無法返回給程式,也就無法得到完整的資料了。

 

 

加一段學習的UDP分包建議:

在進行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)以內.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.