Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在linux中,如果我尽可能快地调用send(),为什么会丢失UDP数据包?_C_Linux_Sockets_Networking_Udp - Fatal编程技术网

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

C 在linux中,如果我尽可能快地调用send(),为什么会丢失UDP数据包?,c,linux,sockets,networking,udp,C,Linux,Sockets,Networking,Udp,隐含的问题是:如果Linux在套接字的发送缓冲区已满时阻止send()调用,为什么会有丢失的数据包 更多详情: 我用C编写了一个小实用程序,将UDP数据包尽可能快地发送到单播地址和端口。我每次发送1450字节的UDP有效负载,第一个字节是一个计数器,每个数据包递增1。我在装有1Gb网卡的台式PC上的Fedora 20 inside VirtualBox上运行它(=相当慢) 然后,我编写了一个从给定端口读取UDP数据包的小实用程序,该程序将数据包的计数器与自己的计数器进行检查,如果数据包的计数器不

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

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

然后,我编写了一个从给定端口读取UDP数据包的小实用程序,该程序将数据包的计数器与自己的计数器进行检查,如果数据包的计数器不同(即丢失了1个或多个数据包),则打印一条消息。我在Fedora20BiXeon服务器上运行它,该服务器带有1Gb以太网nic(=超快)。它确实显示了许多丢失的数据包

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

我尝试过的事情:

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

  • 如果出现过载,您提到的两个路由器中的任何一个都可能丢弃数据包
  • 在某些情况下,例如过载,接收PC也可能丢弃或丢失数据包
即使
send()
在发送缓冲区已满时阻塞(前提是您没有在套接字上设置
SOCK\u NONBLOCK
将其置于非阻塞模式),接收器仍必须足够快,以处理所有传入的数据包。如果接收方或任何中间系统比发送方慢,则在使用UDP时,数据包将丢失。请注意,较慢不仅适用于网络接口的速度,而且适用于整个网络堆栈和用户空间应用程序

在您的情况下,很可能接收方正在接收所有数据包,但在用户空间中处理它们的速度不够快。您可以通过
tcpdump
wireshark
记录和分析流量来检查这一点


如果您不想丢失数据包,请切换到TCP。

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

换句话说,可能会删除数据报而不返回错误(请查看手册页面底部的
ENOBUFS
说明)

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

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

不过,从您所说的来看,虚拟机很可能无法以高速率发送数据包。用
tcpdump(1)
wireshark(1)
尽可能靠近源代码嗅探电线,然后检查序列号-这会告诉你是否是发送者造成的。

正如上面的海报所说,UDP是一种简单的数据报协议,不能保证传输。或者是因为本地机器、网络上的设备等原因。这就是为什么许多当前的开发人员会建议,如果您想要可靠性,切换到TCP的原因。但是,如果您真的想坚持UDP协议,并且有很多合理的理由这样做,那么您需要找到一个库来帮助您保证交付。寻找SS7项目,尤其是在使用UDP传输语音、数据和信令信息的电话API中。对于您的专用应用程序,我建议使用enet UDP库。

我认为这不是一个真正的编程问题。不过有点模糊。谢谢尼古拉。手册页确实声明“当设备队列溢出时,数据包只是被悄悄地丢弃”。这很可能就是那里正在发生的事情。谢谢你指出这一点!