2010-02-18 110 views
37

我有一個Linux應用程序,它打開UDP套接字並等待消息。如何監視Linux UDP緩衝區可用空間?

在重負載下幾個小時後,出現一個數據包丟失,即數據包由內核接收,但不是由我的應用程序接收(我們在嗅探器中看到丟失的數據包,我們看到UDP數據包在netstat中丟失,在我們的應用程序日誌中看到這些數據包)。

我們試圖擴大套接字緩衝區,但這沒有幫助 - 我們之後開始丟包,但就是這樣。

對於調試,我想知道在任何特定時刻OS udp緩衝區有多滿。谷歌搜索,但沒有找到任何東西。你可以幫我嗎?

P.S.夥計們,我知道UDP是不可靠的。但是 - 我的電腦收到所有UDP消息,而我的應用程序無法使用其中的一些消息。我想優化我的應用程序到最大,這就是問題的原因。謝謝。

回答

27

Linux提供文件/proc/net/udp/proc/net/udp6,其中列出了所有打開的UDP套接字(分別針對IPv4和IPv6)。在這兩個列中,列tx_queuerx_queue以字節爲單位顯示傳出隊列和傳入隊列。

如果一切按預期工作,那麼在這兩列中通常不會看到任何不同於零的值:一旦應用程序生成數據包,它們將通過網絡發送出去,並且只要這些數據包從網絡中到達,應用程序將喚醒並接收它們(recv調用立即返回)。如果您的應用程序打開套接字但未調用recv來接收數據,或者它沒有足夠快地處理這些數據,則可能會看到rx_queue

+2

感謝rx_queue,剩下的 - 請參閱更新) – 2010-02-19 05:35:49

+1

@Juliano誰說他可以選擇協議來使用?也許他正在實施基於udp的協議來爲現有客戶提供服務。 – steffen 2013-12-11 10:59:08

+2

海報希望瞭解有關監視UDP統計信息的信息,而不是關於使用哪種協議的意見。通過首先確定層損失發生的位置,然後可以進行修復。 – RickS 2015-05-20 23:10:46

-1

的過程很簡單:

  1. 如果需要的話,暫停該應用程序的過程。

  2. 打開UDP套接字。如有必要,您可以使用/proc/<PID>/fd從正在運行的進程中攔截它。或者,您可以將此代碼添加到應用程序本身併發送一個信號 - 當然,它已經打開套接字。

  3. 儘快致電recvmsg

  4. 計算你得到多少包/字節。

這將丟棄當前緩衝的所有數據報,但是如果這樣會破壞您的應用程序,那麼您的應用程序已被破壞。

+0

我正要降低這個答案,但第二個想到它很搞笑。我只希望沒有人試圖實現這一點:) – Navin 2016-04-09 13:39:50

4

rx_queue會告訴你在任何給定瞬間的隊列長度,但它不會告訴你隊列有多滿,即高水位。無法持續監視此值,也無法以編程方式獲取它(請參閱How do I get amount of queued data for UDP socket?)。

我能想象的監控隊列長度的唯一方法是將隊列移動到您自己的程序中。換句話說,啓動兩個線程 - 一個是儘可能快地讀取套接字並將數據報轉儲到您的隊列中;另一個是你的程序從這個隊列中拉出並處理數據包。這當然假設你可以確保每個線程都在一個單獨的CPU上。現在,您可以監控自己隊列的長度並跟蹤高位標記。

46

UDP是一個完全可行的協議。對於正確的工作來說,正確的工具就是同樣的老案例!

如果你有一個等待UDP數據報的程序,然後在返回等待另一個程序之前處理它們,那麼你的處理時間總是比數據報的最壞情況到達率要快。如果不是,則UDP套接字接收隊列將開始填充。

這可以容忍短爆發。隊列完成它應該做的事 - 排隊數據報,直到你準備好了。但如果平均到達率經常導致隊列積壓,現在是重新設計程序的時候了。這裏有兩個主要的選擇:通過狡猾的編程技術減少處理時間,和/或多線程你的程序。也可以使用跨多個程序實例的負載平衡。

如上所述,在Linux上,您可以檢查proc文件系統以獲取有關UDP的最新狀態。例如,如果我cat/proc/net/udp節點,我得到的是這樣的:

$ cat /proc/net/udp 
    sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops    
    40: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000  0  0 3466 2 ffff88013abc8340 0   
    67: 00000000:231D 00000000:0000 07 00000000:0001E4C8 00:00000000 00000000 1006  0 16940862 2 ffff88013abc9040 2237  
122: 00000000:30D4 00000000:0000 07 00000000:00000000 00:00000000 00000000 1006  0 912865 2 ffff88013abc8d00 0   

從這個,我可以看到,通過用戶ID 1006所擁有的插座,正在偵聽端口0x231D(8989)和接收隊列大約在128KB。由於128KB是我係統上的最大容量,這告訴我我的程序在跟上到達的數據報時非常脆弱。到目前爲止,已經有2237個丟包,這意味着UDP層不能將更多的數據報放入套接字隊列,並且必須丟棄它們。

您可以隨時觀看您的節目的行爲,例如,使用:

watch -d 'cat /proc/net/udp|grep 00000000:231D' 

還要注意netstat命令做的是同一件事:netstat -c --udp -an

我爲我的威尼程序的解決方案,將是多線程。

乾杯!

+0

你怎麼知道你的系統的最大udp隊列大小是128KB? – Chinaxing 2015-01-27 03:47:07

+2

@Chinaxing'cat/proc/sys/net/core/rmem_max' – wakjah 2016-02-02 10:39:14