我有一个网络软件,它使用UDP与同一程序的其他实例进行通信。出于不同的原因,我必须在这里使用UDP。
我最近遇到了通过UDP发送大量数据的问题,并且必须实现一个碎片系统来将我的消息拆分成小数据块。到目前为止,它运行良好但我现在遇到一个问题,当我必须发送很多的数据块。
我有以下算法:
sendto()
然而,当我发送大量数据块时,接收器只获得前6个消息。有时它会错过第六名并获得第七名。这取决于。
无论如何,sendto()
总是表示成功。当我通过环回接口(127.0.0.1)测试我的软件但从未通过我的LAN网络测试我的软件时,总会发生这种情况。
如果我在std::cout << "test" << std::endl;
之间添加sendto()
之类的内容,则会收到每一帧。
我知道UDP允许数据包丢失,并且我的帧可能由于很多原因而丢失,我想它与我发送数据块的速率有关。
这里的方法是什么?
sendto()
之间添加一些任意等待时间是丑陋的,可能会降低性能。我真的需要你的意见。
非常感谢。
我必须使用UDP的原因是因为我有几个约束:
答案 0 :(得分:2)
如果在仅发送6或7个数据包后通过环回接口丢失数据包,则听起来可能是您的接收缓冲区太小。您可以使用SO_RCVBUF选项使用setsockopt增加大小。但是,如果您要发送1500个字节,那么如果这确实是问题,则意味着接收缓冲区仅为大约9K(或者更可能是8K,但这似乎是一个相当小的默认值)。我相信在Windows上默认的接收缓冲区是16K。
即使假设增加接收缓冲区有帮助,您仍然必须解决其他人提到的问题。还有一些需要考虑的事情是尝试动态确定the max packet size以避免碎片。此外,可以手动配置在acks之间发送的数据包大小和数据包数量。
答案 1 :(得分:2)
调用UDP不可靠是一种简化,它试图将TCP作为所有网络疾病的灵丹妙药。同样,将TCP定义为可靠也是错误的。虽然TCP确实存在尝试确保数据传输的机制,但导致UDP数据包故障的许多故障也会导致TCP失败。
例如,硬件网络故障将对UDP和TCP数据包产生相同的影响。如果故障仍然存在,那么TCP将无法像UDP一样通过。实际上在这种情况下,TCP的缺点在于它将尝试更长时间地完成丢失的原因。现在,如果您通过互联网发送数据,TCP具有一些优势,因为无法预定义发送数据包的路由。但是,对于通过LAN发送数据,UDP非常适合。如果您的数据包未到达目的地,则表示需要更正的硬件故障。 TCP在这里没有帮助。
在选择协议时,您还必须了解您的数据。如果您的数据是瞬态的,例如从传感器读取数据,则使用UDP over TCP更有意义。如果在这种情况下数据包丢失,那么由于另一个数据包将很快出现,因此它没什么意义。另一方面,TCP将退回并重试。到数据到达时,它已经过时了。
事实是,TCP是专为流数据而设计的。在这种情况下,重要的是所有数据包都可靠且有序地到达。 UDP用于分组数据,对于这种类型的数据,UDP是完全可以接受的,因为它可靠,开销更少,更快速地检测和恢复网络故障。
答案 2 :(得分:1)
实现确认机制听起来像完全您需要做什么。这样,您可以确保一次“飞行中”不超过N个数据包,并且您可以重新传输未经确认太久的数据包。
答案 3 :(得分:1)
您应该实现确认和重传。要求例如每N个数据包确认一次,并在重传缓冲区中保留N个数据包。
(也许你可以从rudp获得一些想法,或者通过UDP实现Il)
UDP不可靠,也不提供流量控制。简而言之,你会不时地丢失数据包 - 特别是如果你快速发送数据 - 如果没有足够的空间,内核或其间的任何路由器/交换机将丢弃数据包 - 并且你可以采用不用的魔法发生。
答案 4 :(得分:0)
TCP存在以解决这种问题。为什么TCP不是一个选项?您将不得不解决所有相同的问题,并最终得到相同的解决方案,只是没有数十年的TCP堆栈研究,开发和调试的好处。
如果你真的必须使用UDP,首先要问的问题是,你有什么愿意放弃TCP的保证?您是否乐于接收无序的数据包?丢失一定比例的数据包可以吗?你能处理重复数据包的到来吗?这些问题的答案有望导致设计。
在不知道你的具体情况的情况下,用一句简单的话来回答你的问题是不可能的,“做这个,你会没事的”,当然除了“做TCP,你会没事的”。
答案 5 :(得分:0)
UDP传输数据报,并且不可靠。
TCP传输数据流,并且可靠。
您想要的似乎是基于数据报,但可靠。因此,您需要在UDP或TCP上构建一些东西来为您提供。我确信在UDP上有完整的协议规范可以提供。您只需要找到并实施它们。
答案 6 :(得分:0)
无论如何,sendto()总是表示成功。当我通过环回接口(127.0.0.1)测试我的软件但从未通过我的LAN网络测试我的软件时,总会发生这种情况。
如果我添加类似std :: cout&lt;&lt; “test”&lt;&lt;的std :: ENDL;在sendto()之间接收每一帧。
听起来你的接收器缓冲区太小了。
一些建议: