如何监视Linux UDP缓冲区的可用空间?

我有一个Linux上的Java应用程序打开UDP套接字,并等待消息。

在重负载的情况下几个小时后,有一个数据包丢失,即数据包被内核接收,但不是由我的应用程序(我们看到在嗅探器中丢失的数据包,我们看到在netstat丢失的UDP数据包,我们没有看到这些数据包在我们的应用程序日志)。

我们尝试了扩大套接字缓冲区,但这没有帮助 – 我们之后开始丢失数据包,但就是这样。

对于debugging,我想知道在任何时候,操作系统udp缓冲区是多么的充足。 Googlesearch,但没有find任何东西。 你可以帮我吗?

PS伙计们,我知道UDP是不可靠的。 但是 – 我的电脑收到所有UDP消息,而我的应用程序无法使用其中的一些。 我想优化我的应用程序到最大,这就是问题的原因。 谢谢。

Solutions Collecting From Web of "如何监视Linux UDP缓冲区的可用空间?"

Linux提供文件/proc/net/udp/proc/net/udp6 ,它列出了所有打开的UDP套接字(分别为IPv4和IPv6)。 在这两个列中,列tx_queuerx_queue以字节显示输出和输入队列。

如果一切按预期工作,那么在这两列中通常不会看到任何不同于零的值:只要应用程序生成数据包,它们就会通过网络发送出去,一旦这些数据包从网络到达,您的应用程序就会唤醒并接收它们( recv呼叫立即返回)。 如果您的应用程序打开了套接字,但没有调用recv接收数据,或者它没有足够快地处理这些数据,则可能会看到rx_queue

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

我的weenie程序的解决方案,将是多线程。

干杯!

rx_queue会告诉你在任何给定时刻的队列长度,但是它不会告诉你队列有多满,比如高位标记。 没有办法持续监视这个值,也没有办法以编程方式获取它(请参阅如何获得UDP套接字的排队数据量? )。

我能想象的监控队列长度的唯一方法是将队列移动到您自己的程序中。 换句话说,启动两个线程 – 一个是尽可能快地读取套接字并将数据报转储到您的队列中; 另一个是你的程序从这个队列中取出并处理数据包。 这当然假设你可以保证每个线程都在一个单独的CPU上。 现在你可以监视自己队列的长度并跟踪高位标记。

这个过程很简单:

  1. 如果需要,暂停应用程序进程。

  2. 打开UDP套接字。 如有必要,可以使用/proc/<PID>/fd从正在运行的进程中撷取它。 或者,您可以将此代码添加到应用程序本身并发送一个信号 – 当然,它已经打开了套接字。

  3. 尽可能快地调用recvmsg

  4. 计算你得到的数据包/字节数。

这将丢弃当前缓冲的任何数据报,但是如果这打破了你的应用程序,你的应用程序已经被破坏了。