我在linux上有一个java应用程序,它打开UDP套接字并等待消息.
在重负载下经过几个小时后,会丢失数据包,即数据包是由内核接收的,而不是我的应用程序接收的(我们在嗅探器中看到丢失的数据包,我们看到netstat中的UDP数据包丢失,我们看不到这些数据包在我们的app日志中).
我们尝试扩大套接字缓冲区,但这没有任何帮助 - 我们之前开始丢失数据包,但就是这样.
对于调试,我想知道在任何给定时刻OS udp缓冲区的完整性.谷歌搜索,但没有找到任何东西.你能帮助我吗?
PS伙计们,我知道UDP是不可靠的.但是 - 我的计算机接收所有UDP消息,而我的应用程序无法使用其中一些消息.我想优化我的应用程序,这就是问题的原因.谢谢.
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程序的解决方案将是多线程的.
干杯!
Linux提供了文件/proc/net/udp
和/proc/net/udp6
,其中列出所有打开的UDP套接字(IPv4和IPv6,分别).在它们中,列tx_queue
和rx_queue
以字节显示传出和传入队列.
如果一切按预期工作,您通常不会在这两列中看到任何不同于零的值:一旦您的应用程序生成数据包,它们就会通过网络发送,并且一旦这些数据包从网络到达,您的应用程序就会唤醒并接收它们(recv
电话立即返回).rx_queue
如果您的应用程序已打开套接字但未调用recv
接收数据,或者它没有足够快地处理此类数据,您可能会看到上升.