Winsock UDP数据包被丢弃了吗?

我们在Windows中通过UDP设置建立了客户端/服务器通信系统。 我们面临的问题是,当吞吐量增长时,数据包将被丢弃。 我们怀疑这是由于UDP接收缓冲区不断被轮询导致缓冲区被阻塞并丢弃任何传入的数据包。 是否有可能读取此缓冲区将导致传入的数据包被丢弃? 如果是这样,有什么选择来纠正这个? 该系统是用C语言编写的。请告诉我这是否过于模糊,我可以尝试提供更多信息。 谢谢!

Windows套接字中的默认套接字缓冲区大小为8k或8192字节。 使用setsockopt Windows函数来增加缓冲区的大小(请参阅SO_RCVBUF选项)。

但除此之外,如果您没有足够快地读取数据包,增加接收缓冲区的大小只会延迟数据包再次丢弃的时间。

通常,您需要两种线程来处理这种情况。

第一个线程仅用于服务套接字。 换句话说,线程的唯一目的是从套接字读取数据包,将其添加到某种正确同步的共享数据结构,发出已收到数据包的信号,然后读取下一个数据包。

存在第二个线程来处理接收的数据包。 它处于空闲状态,直到第一个线程发出信号通知已收到数据包。 然后,它从正确同步的共享数据结构中提取数据包并对其进行处理。 然后等待再次发出信号。

作为测试,尝试短路数据包的完整处理,并在每次收到数据包时向控制台(或文件)写入一条消息。 如果您可以在不丢弃数据包的情况下成功完成此操作,那么将您的function分解为“接收”线程和“处理”线程将有所帮助。

是的,当缓冲区太满时,允许堆栈丢弃数据包 – 无声地,甚至 – 。 这是UDP性质的一部分,这是您从TCP切换时放弃的可靠性之一。 您可以通过添加重试逻辑,ACK数据包等来重新发明TCP – 或者您可以切换到SCTP之间的某些内容。

有一些方法可以增加堆栈的缓冲区大小,但这在很大程度上忽略了这一点。 如果你没有足够快地读取以保持缓冲区空间可用,那么使缓冲区变大只会延长缓冲区空间耗尽的时间。 正确的解决方案是在您自己的代码中创建更大的缓冲区,并将数据从堆栈的缓冲区移动到程序的缓冲区ASAP中,它可以等待处理任意长时间。

是否有可能读取此缓冲区将导致传入的数据包被丢弃?

如果数据包到达的速度比您读取的速度快,则可以删除数据包。

如果是这样,有什么选择来纠正这个?

一种选择是更改网络协议:使用TCP,或使用UDP实现一些确认+’流量控制’。

否则你需要了解为什么你不能快速/经常阅读。

如果CPU 100%使用,那么您需要为每个数据包执行更少的工作或获得更快的CPU(或者如果您还没有使用multithreading和更多CPU)。

如果CPU不是100%,那么可能正在发生的事情是:

  • 你读了一个包
  • 你做了一些工作,需要x毫秒的实时,其中一些在其他I / O上被阻塞(所以CPU不忙,但它没有被用来读取另一个数据包)
  • 在那些x毫秒期间,大量数据包到达,一些数据包被丢弃

解决这个问题的方法是改变线程。

另一种可能性是从套接字执行几个同时读取(每个读取提供一个可以接收UDP数据包的缓冲区)。

另一种可能性是查看是否存在(O / S特定的)配置选项来增加网络堆栈愿意缓冲的接收UDP数据包的数量,直到您尝试读取它们为止。

第一步,增加接收器缓冲区大小,Windows几乎授予所有合理大小的请求。

如果这没有帮助,您的消费代码似乎有一些相当慢的区域。 我会使用线程,例如使用pthreads并利用生产者消费者模式将传入的数据报放在另一个线程的队列中,然后从那里消耗,因此你的接收调用不会阻塞,缓冲区也不会运行

第3步,修改您的应用程序级协议,允许发送方的批处理数据包和批处理数据包,以减少发送大量小数据包的UDP报头开销。

第4步检查您的网络设备,交换机等,可以为您提供有关其流量统计,缓冲区溢出等的详细输出 – 如果有问题,可以获得更快的交换机或可能切换出故障的交换机

…只是fyi,我正在我们的后端连续运行UDP多播流量。 ~30Mbit / sec,峰值为70Mbit / s,我的丢弃率为零

不确定这一点,但在Windows上,它不可能轮询套接字并导致数据包丢失。 Windows从轮询中单独收集数据包,不应导致任何丢弃。

我假设你使用select()来轮询套接字? 据我所知,不能导致跌落。