UDP数据包丢失 - INErrors与RcvbufErrors的区别

21
我编写了一个简单的UDP服务器程序,以更好地了解可能存在的网络瓶颈。
UDP服务器:创建一个UDP套接字,将其绑定到指定的端口和地址,并将套接字文件描述符添加到epoll兴趣列表中。然后,它的epoll等待传入的数据包。在接收到传入的数据包(EPOLLIN)时,它会读取该数据包并打印接收到的数据包长度。非常简单,对吧 :)
UDP客户端:我使用如下所示的hping:
hping3 192.168.1.2 --udp -p 9996 --flood -d 100
当我每秒发送100个udp数据包时,我没有发现任何UDP数据包丢失。但是当我洪水般地发送udp数据包(如上述命令所示),我看到显着的数据包丢失。
测试1: 当从UDP客户端洪泛26356个数据包时,我的样本程序仅接收到12127个数据包,其余的14230个数据包被内核丢弃,如/proc/net/snmp输出所示。

cat /proc/net/snmp | grep Udp:
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
Udp: 12372 0 14230 218 14230 0

对于Test1,数据包丢失率约为53%。

我使用“ethtool -S ethX”命令在客户端和服务器端都验证了硬件级别上没有太多的丢失,但在应用程序级别上,如上所述,我看到了53%的丢失。

因此,为了减少数据包丢失,我尝试了以下方法:
- 使用命令增加了我的示例程序的优先级。
- 增加接收缓冲区大小(系统级别和进程级别都要增加)

将优先级提高到-20:

renice -20 2022
2022(进程ID)旧优先级为0,新优先级为-20

将接收缓冲区大小增加到16MB:

在进程级别:
int sockbufsize = 16777216;
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,(char *)&sockbufsize, (int)sizeof(sockbufsize))
在内核级别:
cat /proc/sys/net/core/rmem_default
16777216
cat /proc/sys/net/core/rmem_max
16777216

完成这些更改后,执行Test2。

Test2: 当从UDP客户端发送1985076个数据包时,我的样例程序接收了1848791个数据包,其余的136286个数据包被内核丢弃,如/proc/net/snmp输出所示。

cat /proc/net/snmp | grep Udp:
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
Udp: 1849064 0 136286 236 0 0

对于Test2数据包丢失率为6%。

数据包丢失率已经显著降低。但我有以下问题:

  1. 数据包丢失率是否可以进一步减少?!?我知道这很贪心 :) 但我只是想找出是否可以进一步减少数据包丢失。
  2. 与Test1不同,在Test2中InErrors与RcvbufErrors不匹配,而RcvbufErrors始终为零。有人能解释一下原因吗?!? InErrors和RcvbufErrors之间到底有什么区别。我了解RcvbufErrors但不了解InErrors。

感谢您的帮助和时间!!!


我知道这是一个古老的问题,但你找出了这个问题的核心吗?我正在尝试复现InErrors > RcvbufErrors条件。 - mgjk
3个回答

10
调整Linux内核的网络堆栈以减少数据包丢失有些复杂,因为从驱动程序一直到网络堆栈都有很多调整选项。 我写了一篇长篇博客文章,从上到下解释了所有调整参数,并解释了/proc/net/snmp中每个字段的含义,这样您就可以弄清楚为什么会出现这些错误。看一下,我认为它应该能帮助您将网络丢包降至0。

2
长篇博客文章是一个失效的链接。 - GroovyDotCom
@GroovyDotCom,更新后的链接应该是:https://blog.packagecloud.io/monitoring-tuning-linux-networking-stack-receiving-data/。 - ks1322
这是一篇很棒的文章。 - Alex Velickiy

1
如果硬件层面没有丢包,那么问题大多在于内存,您可以调整内核配置参数以达到0丢包(显然,您需要一个合理平衡的硬件来处理网络流量)。
我认为您缺少netdev_max_backlog,这对于传入的数据包非常重要:
最大数量的数据包,在接口接收数据包比内核能够处理它们更快时,在输入端排队。

0

InErrors由以下组成:

  • 损坏的数据包(不正确的标头或校验和)
  • 接收缓冲区大小已满

因此,我的猜测是您已经解决了缓冲区溢出问题(RcvbufErrors为0),剩下的是具有不正确校验和的数据包。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接