4

我有一个网络软件,它使用 UDP 与同一程序的其他实例进行通信。由于不同的原因,我必须在这里使用 UDP。

我最近在通过 UDP 发送大量数据时遇到了问题,我不得不实现一个分片系统来将我的消息分成小数据块。到目前为止,它运行良好,但是当我必须发送大量数据块时,我现在遇到了一个问题。

我有以下算法:

  1. 将消息拆分成小数据块(大约 1500 字节)
  2. 遍历数据块列表,并为每一个,使用发送它sendto()

但是,当我发送大量数据块时,接收方只收到前 6 条消息。有时它会错过第六个而收到第七个。这取决于。

不管怎样,sendto()总是预示着成功。当我通过环回接口 (127.0.0.1) 测试我的软件但从未通过我的 LAN 网络测试我的软件时,总是会发生这种情况。

std::cout << "test" << std::endl;如果我在之间添加类似的东西,sendto()那么每一帧都会被接收到。

我知道 UDP 允许数据包丢失,并且我的帧可能由于很多原因而丢失,我想这与我发送数据块的速率有关。

这里的正确方法是什么?

  • 实现一些确认机制(就像 TCP 一样)似乎有点过头了。
  • 在两者之间添加一些任意等待时间sendto()是丑陋的,并且可能会降低性能。
  • 增加(如果可能的话)接收方 UDP 内部缓冲区?我什至不知道这是否可能。
  • 还有什么?

我在这里真的需要你的建议。

非常感谢。

应要求提供的附加信息

必须使用 UDP 的原因是因为我有几个限制:

  1. TCP 不能很好地与 NAT 遍历一起工作(至少在没有特定配置的情况下)
  2. 有些消息可能会丢失。有些人不能。
  3. 消息传递顺序无关紧要。
4

7 回答 7

2

如果您在仅发送 6 或 7 个数据包后通过环回接口丢失数据包,那么听起来您的接收缓冲区可能太小了。您可以使用 SO_RCVBUF 选项通过setsockopt增加大小。但是,如果您要发送 1500 个字节,那么如果这确实是问题所在,则意味着接收缓冲区只有大约 9K(或更可能是 8K,但这似乎是一个相当小的默认值)。我相信在 Windows 上默认接收缓冲区是 16K。

即使假设增加接收缓冲区有帮助,您仍然必须解决其他人提到的问题。需要考虑的其他几件事可能是尝试动态确定最大数据包大小以避免碎片。此外,手动配置在 ack 之间发送的数据包大小和数据包数量可能是有意义的。

于 2010-04-18T13:43:28.677 回答
2

称 UDP 不可靠是一种简化,它试图将 TCP 视为所有网络疾病的灵丹妙药。同样,将 TCP 定义为可靠也是错误的。虽然 TCP 确实具有尝试确保数据传输的机制,但许多导致 UDP 数据包无法到达的故障也会导致 TCP 失败。

例如,硬件网络故障将对 UDP 和 TCP 数据包产生相同的影响。如果故障仍然存在,那么 TCP 将不会像 UDP 那样可靠地通过。事实上,在这种情况下,TCP 的缺点在于它会尝试更长时间地完成丢失的原因。现在,如果您通过 Internet 发送数据,TCP 具有一些优势,因为无法预定义发送数据包的路由。然而,对于通过 LAN 发送数据,UDP 就足够了。如果您的数据包没有到达目的地,则表明存在需要纠正的硬件故障。TCP 在这里无济于事。

此外,在选择您的协议时,您还必须了解您的数据。如果您的数据是瞬态的,例如来自传感器的读数,则使用 UDP over TCP 会更有意义。如果在这种情况下丢失了一个数据包,那么它的影响很小,因为另一个数据包很快就会出现。另一方面,TCP 将退出并重试。当数据到达时,它已经过时了。

事实上,TCP 是为流数据设计的。在这种情况下,重要的是所有数据包都可靠且有序地到达。UDP 用于数据包数据并且用于这种类型的数据 UDP 是完全可以接受的,因为它可靠、开销更少并且可以更快地检测到网络故障并从网络故障中恢复。

于 2012-01-17T18:46:30.583 回答
1

实施确认机制听起来正是您需要做的。这样,您可以确保一次“进行中”的数据包不超过 N 个,并且您可以重新传输长时间未确认的数据包。

于 2010-04-18T12:45:54.670 回答
1

您应该实施确认和重传。例如,要求每 N 个数据包确认一次,并将 N 个数据包保留在您的重传缓冲区中。

(也许你可以从rudp获得一些想法,或者通过 UDP实现Il )

UDP 不可靠,也没有提供流量控制。简短的故事是,你会不时丢失数据包 - 特别是如果你快速发送数据 - 如果没有足够的空间,内核或中间的任何路由器/交换机都会丢弃数据包 - 你可以使用一点魔法来避免这种情况发生。

于 2010-04-18T12:55:10.457 回答
0

TCP的存在就是为了解决这类问题。为什么 TCP 不是一个选项?您将不得不解决所有相同的问题并最终得到相同的解决方案,只是没有受益于 TCP 堆栈数十年的研究、开发和调试。

如果你真的必须使用 UDP,首先要问的问题是,你愿意放弃 TCP 的保证吗?您是否乐于收到乱序的数据包?丢失一定百分比的数据包可以吗?你能处理重复数据包的到来吗?这些问题的答案有望带来设计。

在不了解您的具体情况的情况下,不可能用简单的“这样做,你会没事的”来回答你的问题,当然,除了“做 TCP,你会没事的”。

于 2010-04-18T12:48:46.430 回答
0

UDP传输数据报,不可靠。

TCP传输数据流,是可靠的。

您想要的似乎是基于数据报的,但可靠。所以你需要在 UDP 或 TCP 上构建一些东西来给你。我确信在 UDP 上构建了完整的协议规范来提供这一点。您只需要找到并实施它们。

于 2010-04-18T13:01:07.103 回答
0

无论如何, sendto() 总是表示成功。当我通过环回接口 (127.0.0.1) 测试我的软件但从未通过我的 LAN 网络测试我的软件时,总是会发生这种情况。

如果我添加类似 std::cout << "test" << std::endl; 在 sendto() 之间,然后接收到每一帧。

听起来您的接收器缓冲区太小了。

一些忠告:

  1. 增加接收缓冲区。setsockopt SO_RCVBUF
  2. 让应用程序决定是否重传丢失的包。
  3. 确保有效负载适合 MTU,即有效负载 + HEADER <= 1500,以避免 ip 碎片。
于 2014-10-21T01:53:19.647 回答