“正确”的方式发送一系列UDP数据报?

时间:2009-05-20 13:10:00

标签: c++ winapi udp messaging

我的印象是UDP的不稳定性是物理层的属性,但似乎不是:

我正在尝试通过UDP发送消息,UDP分为一系列数据包。消息识别和重新排序是隐式完成的。

我在同一台计算机上运行的两个应用程序上测试了这种方法,并期望它能够顺利运行。然而,即使数据传输在同一台机器上的两个程序之间,也存在数据包丢失,并且也非常频繁。损失似乎也是随机的:有时整个信息都会通过,有时候不会。

现在,即使在同一台机器上发生损失的事实,让我想知道我做得对吗?

最初,我在一次拍摄中异步发送了所有消息的peices,而不是在发送下一个之前等待完成一个peice。

然后,我尝试从前一个完成例程中发送下一条消息。这确实提高了数据包丢失率,但并没有完全阻止它。

如果我在peices之间添加了一个暂停(Sleep(...)),它可以100%工作。

修改 正如回答所建议的那样:数据包发送速度太快,操作系统的缓冲最小。这是合乎逻辑的。

所以,如果我想阻止在系统中添加确认和重新传输(那时我可以使用TCP),我该怎么办?在不将数据速率降低到可能更高的水平的情况下,提高数据包丢失率的最佳方法是什么?

编辑2: 它发生在我身上,问题可能不是完全缓冲区溢出,而不是缓冲区可用性。 我正在使用异步WSARecvFrom来接收,根据我的理解,它会占用一个缓冲区来覆盖默认的OS缓冲区。 当收到数据报时,它被送入缓冲区,并且在缓冲区已满或不满时调用完成例程。

此时,根本没有缓冲区来处理传入的数据,直到从完成例程中重新调用WSARecvFrom。

问题是如果有办法创建某种缓冲池,那么在处理不同的缓冲区时可以缓冲数据吗?

7 个答案:

答案 0 :(得分:6)

在您的情况下,您只是过快地发送数据包,以便接收进程读取它们。 O / S只会在开始丢弃之前缓冲一定数量的接收数据包。

避免这种情况的最简单的机制是让接收进程发送回最小的ACK数据包,但是无论是否在几毫秒左右没有收到ACK,发送过程就会继续进行。

编辑 - 基本上,UDP是“火上浇油”。协议中没有内置的反馈机制,就像TCP一样。调整传输速率的唯一方法是远端告诉您它没有接收整个流。另请参阅RFC 2309


Re:数据包序列 - 由于物理层不会发生重新排序,通常是因为IP网络是“分组交换”而不是“电路交换”。

这意味着每个数据包可能在网络中采用不同的路由,并且由于这些不同的路由可能具有不同的延迟,因此数据包可能无序到达。

在实践中,由于物理层错误,目前很少有数据包丢失。数据包丢失是因为它们以高于管道可容纳的速率被送入有限吞吐量管道。缓冲可以通过平滑数据包流速来帮助实现这一点,但是如果缓冲区填满,则会回到正方形。

答案 1 :(得分:3)

为了避免OS缓冲区的问题,您需要实现速率控制系统。它可以是闭环的(接收器发回ACK和关于它的缓冲区的信息)或开环(发送者减慢自身速度,这意味着你必须保守)。

UDP有半标准协议来实现这两种协议。想到了RBUDP(Reliable Blast UDP),还有其他人。

答案 2 :(得分:2)

如果你正在使用UDP,据我所知,检测数据包丢失的唯一方法是涉及某种反馈。如果您在具有相当一致吞吐量的网络上,您可以执行一个训练期,在此期间您发送数据突发并等待接收器响应并告诉您收到的突发中有多少数据包(即使接收器计数和超时后,用它得到的号码回复。然后你只需要增加每次爆发的数据量,直到达到极限并稍微降低一点以确保。

这可以避免在初始评估期后的确认,但只有在网络/接收过程中的负载没有改变时才会起作用。

我以前在Python中编写了UDP客户端,并且我发现任何重大数据包丢失的唯一时间是接收进程上的输入缓冲区太小。因此,当系统负载很重时,您会丢失数据包,因为缓冲区会无声地溢出。

答案 3 :(得分:1)

如果您将WSA_FLAG_OVERLAPPED标记传递给WSASocket(),则可以多次调用WSARecvFrom()以排队多个接收I / O请求。这样,即使在完成例程排队另一个I / O请求之前,还有另一个缓冲区可用于接收下一个数据包。

这并不一定意味着您不会丢弃数据包。如果你的程序没有足够快地提供足够的缓冲区,或者处理它们并重新排队它们需要很长时间,那么它将无法跟上,而且当某种速率限制可能有用时。< / p>

答案 4 :(得分:0)

我怀疑你的机器的IP层无法像你发送的那样快速传输。

可能因为协议允许丢弃数据包,而另一个目标 - 尽可能快地传输数据包 - 否则无法实现。

您的计算机上的其他流量或CPU使用过程可以解释不同的结果,您在测试期间使用top(unix)或prcess explorer(nt)进行了观察吗?

答案 5 :(得分:0)

你必须做错事。丢失数据包的唯一方法是1)不可靠的网络2)您发送的数据太快,无法由您的接收程序处理。 3)您发送的邮件大于UDP最大邮件大小4)网络中的每个设备都有最大邮件大小(MTU),因此您可能超出限制。

在#1的情况下,由于您在同一台计算机上发送,因此网络甚至没有涉及,因此它应该100%可靠。你没有说你有2张网卡,所以我不认为这是一个问题。

在#2的情况下,在开始删除数据之前,通常需要发送大量数据。根据你的描述,这听起来并非如此。

如果是#3,请确保您的所有邮件都低于此限制。

在#4的情况下,我很确定你是否符合UDP最大邮件大小,那么你应该没问题,但很可能是一些较旧的硬件或具有小MTU的自定义设备,你的数据正在通过。如果是这种情况,则会以静默方式丢弃这些数据包。

我在许多应用程序上使用过UDP,它已被证明非常可靠。您使用MFC接收消息吗?如果您是,那么您需要非常仔细地阅读文档,因为它们清楚地说明了您需要注意的一些问题,但大多数人只是掩盖它们。当人们无法弄清楚为什么消息不能正常工作时,我不得不解决相当多的光泽问题。

编辑:您说您的数据包是隐式重新排序的。我可能首先验证您的隐式重新排序是否真的正常工作。这似乎是你问题最有可能的候选人。

编辑#2:您是否尝试过使用网络监视器?微软已经(或者至少习惯了)一个名为“网络监视器”的免费程序可能会有所帮助。

答案 6 :(得分:-1)

看起来OS缓冲无法跟上频率较低的上下文切换,即低级别发送需要更频繁的上下文切换。检查是否有办法优化低级发送缓冲区大小。