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

标签 c linux sockets networking udp

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

更多详情: 我用 C 编写了一个小实用程序,以尽快将 UDP 数据包发送到单播地址和端口。我每次发送一个 1450 字节的 UDP 负载,第一个字节是一个计数器,每个数据包递增 1。我在配备 1Gb 网卡(=相当慢)的台式机上的 VirtualBox 内的 Fedora 20 上运行它。

然后我编写了一个小实用程序来从给定端口读取 UDP 数据包,它根据自己的计数器检查数据包的计数器并打印一条消息,如果它们不同(即 1 个或多个数据包已丢失)。我在带有 1Gb 以太网网卡(=超快)的 Fedora 20 双至强服务器上运行它。它确实显示了许多丢失的数据包。

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

我尝试过的事情:

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

请赐教!

最佳答案

对于 UDP,SO_SNDBUF 套接字选项仅限制您可以发送的数据报的大小。与 TCP 一样,没有显式限制发送套接字缓冲区。当然,网卡的帧在内核中排队。

换句话说,send(2)可能会在不返回错误的情况下丢弃您的数据报(查看手册页底部的 ENOBUFS 的描述)。

然后数据包可能会在路径上的几乎任何地方被丢弃:

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

不过从你所说的来看,VM 无法以高速率发送数据包的可能性很大。使用 tcpdump(1)wireshark(1) 尽可能靠近源嗅探线路,并检查您的序列号 - 它会告诉您是否是发件人是罪魁祸首。

关于c - 在 Linux 中,如果我尽可能快地调用 send() 为什么会丢失 UDP 数据包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29628555/

相关文章:

c++ - 套接字编程中的select()c++总是给出时间错误

c - 为什么这不能正确执行?为什么它不从用户那里获取 rpm 值?

c - 两个链表的交集

c++ - list.h list_del() 给出内核分页错误

php - ReactPHP 套接字服务器 : What triggers the write (to client)?

node.js - Nodejs套接字连接错误

c-copy_to_user : how to read a struct type value of kernel space in the user space?

c - C 和 mmap() 中 & 代表什么

c - 第二次读取内核会覆盖第一次实例

linux - Linux 服务器中的磁盘空间