使用UDP套接字的多个sendto()

时间:2010-04-18 12:39:14

标签: c sockets udp portability sendto

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

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

我有以下算法:

  1. 将消息拆分为小数据块(大约1500字节)
  2. 迭代数据块列表,并为每个列表使用sendto()
  3. 发送

    然而,当我发送大量数据块时,接收器只获得前6个消息。有时它会错过第六名并获得第七名。这取决于。

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

    如果我在std::cout << "test" << std::endl;之间添加sendto()之类的内容,则会收到每一帧。

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

    这里的方法是什么?

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

    我真的需要你的意见。

    非常感谢。

    所要求的其他信息

    必须使用UDP的原因是因为我有几个约束:

    1. 使用NAT遍历(至少没有特定配置),TCP无法正常运行
    2. 某些消息可能丢失。其他一些人不能。
    3. 邮件传递顺序无关紧要。

7 个答案:

答案 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()之间接收每一帧。

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

一些建议:

  1. 增加接收器缓冲区。 setsockopt SO_RCVBUF
  2. 让应用程序决定是否重传丢包。
  3. 确保有效负载符合MTU,这意味着有效负载+ HEADER <= 1500,以避免ip碎片化。