代码之家  ›  专栏  ›  技术社区  ›  Yoni Roit

如何监控linux-udp缓冲区的可用空间?

  •  41
  • Yoni Roit  · 技术社区  · 15 年前

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

    在重负载下运行几个小时后,会出现数据包丢失,即数据包由内核接收,而不是由我的应用程序接收(我们在sniffer中看到丢失的数据包,在netstat中看到丢失的UDP数据包,在我们的应用程序日志中看不到这些数据包)。

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

    对于调试,我想知道在任何给定的时刻,OSUDP缓冲区有多满。谷歌搜索,但没有找到任何东西。你能帮助我吗?

    伙计们,我知道UDP是不可靠的。但是-我的计算机接收所有的UDP消息,而我的应用程序无法使用其中的一些消息。我想最大限度地优化我的应用程序,这就是问题的原因。谢谢。

    4 回复  |  直到 9 年前
        1
  •  35
  •   Juliano    9 年前

    Linux提供文件 /proc/net/udp /proc/net/udp6 ,其中列出了所有打开的UDP套接字(分别针对IPv4和IPv6)。在这两列中, tx_queue rx_queue 以字节为单位显示传出和传入队列。

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

        2
  •  54
  •   Søren Løvborg    11 年前

    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程序解决方案是多线程。

    干杯!

        3
  •  4
  •   Community CDub    8 年前

    Rx_队列将告诉您任何给定时刻的队列长度,但它不会告诉您队列已满,即高位标记。没有办法持续监控这个值,也没有办法以编程方式获取它(请参见 How do I get amount of queued data for UDP socket? )

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

        4
  •  0
  •   David Schwartz    13 年前

    过程很简单:

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

    2. 打开UDP套接字。您可以使用 /proc/<PID>/fd 如有必要。或者您可以将此代码添加到应用程序本身并向其发送一个信号——当然,它已经打开了套接字。

    3. 呼叫 recvmsg 尽可能快地形成一个紧密的循环。

    4. 计算您得到了多少数据包/字节。

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