在linux中,如果我尽可能快地调用send(),为什么我会丢失UDP数据包?

see*_*ker 9 c sockets linux networking udp

隐含的问题是:如果Linux send()在套接字的发送缓冲区已满时阻塞了调用,为什么会有丢包?

更多细节:我在C中编写了一个小实用程序,以尽可能快地将UDP数据包发送到单播地址和端口.我每次发送一个1450字节的UDP有效载荷,第一个字节是一个计数器,每个数据包递增1.我在具有1Gb nic(=非常慢)的台式PC上的VirtualBox内部的Fedora 20上运行它.

然后我写了一个小实用程序来读取来自给定端口的UDP数据包,该端口检查数据包的计数器与其自己的计数器,如果它们不同(即1个或更多数据包丢失)则打印一条消息.我在Fedora 20 bi-xeon服务器上运行它,它具有1Gb以太网网络(=超快速).它确实显示了许多丢失的数据包

两台机器都在本地网络上.我不确切知道它们之间的跳数,但我不认为它们之间有超过2个路由器.

我试过的事情:

  • 每次之后添加延迟send().如果我设置1ms的延迟,则不再丢失数据包.延迟100us将开始丢失数据包.
  • 使用接收套接字缓冲区大小增加到4MiB setsockopt().这没有任何区别......

请赐教!

Nik*_*sov 9

对于UDP,SO_SNDBUF套接字选项仅限制可以发送的数据报的大小.与TCP一样,没有明确的限制发送套接字缓冲区.当然,内核将帧排队到网卡.

换句话说,send(2)可能会丢弃您的数据报而不返回错误(请查看ENOBUFS手册页底部的说明).

然后,数据包可能会在路径上的任何位置丢弃:

  • 发送网卡没有免费的硬件资源来处理请求,丢弃帧,
  • 中间路由设备没有可用的缓冲区空间或实现一些拥塞避免算法,丢弃数据包,
  • 接收网卡不能接受给定速率的以太网帧,有些帧只是被忽略.
  • reader应用程序没有足够的套接字接收缓冲区空间来容纳流量峰值,内核丢弃数据报.

从你所说的话来看,VM很可能无法以高速率发送数据包.使用tcpdump(1)或wireshark(1)尽可能靠近源嗅探电线,并检查您的序列号 - 这将告诉您是否应该责怪发件人.