sendto頻率過快導致發送丟包


編寫一個轉發模塊,雖然沒有要求一轉多時要達到多少路(不采用組播的情況下,單純的一路轉成多路),但是本着物盡其用的原則,盡可能測試一下極限。

網絡環境:1000M,直連,多網卡

系統:Linux version 3.19.0

接收模式:udp模式的raw socket(優化的話,可以直接通過網卡處理)

發送模式:udp模式的raw socket(優化的話,可以直接通過網卡處理),單線程/多線程

                     2M               1轉N

設備A   ---------------->   轉發設備  ---------------->  設備B

 

但N大到一定程度時,發現發送丟包。

注意,是轉發設備發送丟包,不是設備B接收丟包。

設備B接收丟包是可以理解的,畢竟2M碼率本身的突發性相當高,1轉N時,這個突發率更加擴大。

但是發送丟包是一個什么情況,sendto的返回值都進行了判斷,如果異常是會出現打印信息的,但是沒有異常出現。

上網查資料。其中最靠譜的是

http://www.cnblogs.com/mengyan/archive/2012/10/04/2711340.html

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.”(一秒鍾幾個數據包不算什么,但是一秒鍾成百上千的數據包就不好辦了)。

 

發送方丟包:內部緩沖區(internal buffers)已滿,並且發送速度過快(即發送兩個報文之間的間隔過短); 

但是更讓人郁悶的事情出現了。無論是網上資料,還是詢問同事,與tcp不同,發送這一塊沒有緩存區啊。

問題的,已經設置SO_SNDBUF為64M,修改系統值為128M,設置后獲取到的SO_SNDBUF為128M。

現在就是在此種情況下發送丟包,128M是什么概念啊,所以基本可以排除這一塊的問題。

通過命令watch netstat -s,可以明確的看出 Ip 項下的 outgoing packets dropped 持續增長,也就意味着確實是發送丟包。

然后就通過outgoing packets dropped ,sendto頻率過快等等關鍵詞開始查資料,結果讓人藍瘦香菇啊

陰差陽錯的情況下,查到了 IOCTLS

http://blog.csdn.net/wl_haanel/article/details/5305159

SIOCGIFTXQLEN , SIOCSIFTXQLEN
使用 ifr_qlen 讀取 或 設置 設備的 傳輸隊列長度. 設置 傳輸隊列長度 是 特權操作.

 

於是通過

struct ifreq ifr;

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));

if (-1 == ioctl(sock_, SIOCGIFTXQLEN, &ifr))
    PLOG(ERROR) << "failed to get dev eth0 queue length";
LOG(KEY) << "Dev eth0 queue length " << ifr.ifr_qlen;

獲取到eth0上的隊列長度為1000,設置成10000試試

struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
ifr.ifr_qlen = 10000;
if (-1 == ioctl(sock_, SIOCSIFTXQLEN, &ifr))
  PLOG(ERROR) << "failed to set dev eth0 queue length";
if (-1 == ioctl(sock_, SIOCGIFTXQLEN, &ifr))
  PLOG(ERROR) << "failed to get dev eth0 queue length";
LOG(KEY) << "Dev eth0 queue length " << ifr.ifr_qlen;

果然,發現好了,沒有發送丟包了

去掉SO_SNDBUF的設置,獲取下SO_SNDBUF,才多少K,再測試,仍然沒有發送丟包。

 

結論:

sendto過快導致發送丟包,是因為發送隊列滿了,如果說緩存區,估計大部分人都將誤解。

 

至於接收方因為突發率導致接收丟包的問題,那么就要在發送方進行發送平滑進行解決。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM