我们在Windows中通过UDP设置建立了客户端/服务器通信系统。我们面临的问题是,当吞吐量增长时,数据包会被丢弃。我们怀疑这是由于UDP接收缓冲区不断被轮询导致缓冲区被阻塞并丢弃任何传入的数据包。是否有可能读取此缓冲区将导致传入的数据包被丢弃?如果是这样,有什么选择来纠正这个?该系统是用C语言编写的。请告诉我这是否过于模糊,我可以尝试提供更多信息。谢谢!
答案 0 :(得分:12)
Windows套接字中的默认套接字缓冲区大小为8k或8192字节。使用setsockopt Windows函数增加缓冲区的大小(请参阅SO_RCVBUF选项)。
但除此之外,如果您没有足够快地读取数据包,增加接收缓冲区的大小只会延迟数据包再次丢弃的时间。
通常,您需要两种线程来处理这种情况。
第一个线程仅用于服务套接字。换句话说,线程的唯一目的是从套接字读取数据包,将其添加到某种正确同步的共享数据结构,发出已收到数据包的信号,然后读取下一个数据包。
存在第二个线程来处理收到的数据包。它处于空闲状态,直到第一个线程发出信号通知已收到数据包。然后,它从正确同步的共享数据结构中提取数据包并对其进行处理。然后等待再次发出信号。
作为测试,请尝试缩短数据包的完整处理速度,并在每次收到数据包时向控制台(或文件)写入消息。如果你可以成功地做到这一点而不丢弃数据包,那么将你的功能分解为“接收”线程和“处理”线程将有所帮助。
答案 1 :(得分:5)
是的,当缓冲区太满时,允许堆栈丢弃数据包 - 无声地,甚至 - 。这是UDP性质的一部分,这是您从TCP切换时放弃的可靠性之一。您可以通过添加重试逻辑,ACK数据包等来重新发明TCP - 或者您可以切换到SCTP之间的某些内容。
有一些方法可以增加堆栈的缓冲区大小,但这在很大程度上忽略了这一点。如果你没有足够快地读取以保持缓冲区空间可用,那么使缓冲区变大只会延长缓冲区空间耗尽的时间。正确的解决方案是在您自己的代码中创建更大的缓冲区,并将数据从堆栈的缓冲区移动到程序的缓冲区ASAP中,它可以等待任意长时间处理。
答案 2 :(得分:3)
读取此缓冲区是否可能导致传入数据包被丢弃?
如果数据包到达的速度比您阅读的速度快,则可以删除数据包。
如果有,有哪些方法可以解决这个问题?
一种选择是更改网络协议:使用TCP,或使用UDP实现一些确认+'流量控制'。
否则你需要了解为什么你不能快速/经常阅读。
如果CPU 100%使用,那么你需要减少每个数据包的工作量或获得更快的CPU(或者如果你还没有使用多线程和更多的CPU)。
如果CPU不是100%,那么可能正在发生的事情是:
解决这个问题的方法是改变线程。
另一种可能性是从套接字执行多个同时读取(每个读取提供一个可以接收UDP数据包的缓冲区)。
另一种可能性是查看是否存在(特定于O / S)配置选项来增加网络堆栈愿意缓冲的接收UDP数据包的数量,直到您尝试读取它们为止。
答案 3 :(得分:3)
第一步,增加接收器缓冲区大小,Windows几乎授予所有合理大小的请求。
如果这没有帮助,您的消费代码似乎有一些相当慢的区域。我会使用线程,例如使用pthreads并利用生产者消费者模式将传入的数据报放在另一个线程的队列中然后从那里消耗,因此你的接收调用不会阻塞,缓冲区也不会运行完全
第3步,修改你的应用程序级协议,允许发送方的批处理数据包和批处理数据包,以减少发送大量小数据包的UDP报头开销。
第4步检查您的网络设备,交换机等可以为您提供有关其流量统计信息,缓冲区溢出等的详细输出 - 如果有问题可以获得更快的交换机或可能切换出错误的交换机
...只是fyi,我正在我们的后端连续运行UDP多播流量。 ~30Mbit / sec,峰值为70Mbit / s,我的丢弃率为零
答案 4 :(得分:0)
不确定这一点,但在Windows上,它无法轮询套接字并导致数据包丢失。 Windows会从轮询中单独收集数据包,并且不会导致任何丢弃。
我假设您使用select()轮询套接字?据我所知,不能导致跌落。
答案 5 :(得分:0)
由于路径中任何位置的无关网络流量增加或完整接收缓冲区,数据包可能会丢失。为了缓解这种情况,您可以在Winsock中增加接收缓冲区大小。
从本质上讲,UDP是一种不可靠的协议,因为无法保证数据包传输,并且在传递失败时不会向发送方返回任何错误。如果您担心数据包丢失,最好将确认数据包实施到您的通信协议中,或将其移植到更可靠的协议(如TCP)。确实没有其他真正可靠的方法来防止UDP数据包丢失。