2010-02-18 113 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