如何使用C# UdpClient发送大数据?

12

我正在尝试使用C#的UdpClient发送大量数据(超过50 MB)。

因此,我首先将数据分成65507字节块并在循环中发送它们。

for(int i = 0; i < packetCount; i++)
   myUdpClient.Send(blocks[i], block[i].Length, remoteEndPoint);

我的问题是只有第一个数据包能够被接收。在发送第一个数据包时,网络负载迅速增加到100%,然后其他数据包无法被接收。

我想尽可能地获得数据吞吐量。

对于我的英语表示抱歉! 提前感谢您的帮助。


如果您不拆分数据会发生什么? - leppie
使用微软网络监视器3.3查看数据包并确认到达。 - lsalamon
如果我不拆分数据,udpClient.Send调用将会失败,因为超过了最大的UDP数据包大小。 - raisyn
4个回答

11

对于那些建议使用TCP的人,他们是错误的。虽然TCP是可靠的,并且由内核维护的窗口是一个相当“设置和忘记”的协议,但是当涉及到想要使用100%吞吐量的人时,TCP不起作用(它会限制太多,并且等待ACK至少会因RTT延迟50%)。

就原问题而言,在该for循环中不停地发送UDP数据包,窗口填满后,任何新数据都会立即丢弃,甚至不会尝试上线。您还将数据拆分得过大。我建议构建自己的节流机制,每秒开始使用2k个片段,慢慢升高。 每个“段”包含SEQ(确认或ACK的序列标识符)和OFF(此数据集合的文件内偏移量)。在标记数据时,让服务器跟踪这些标记。当另一侧收到它们时,它会将SEQ数字存储在ACK列表中,任何缺失的SEQ数字都会放入NACK计时器列表中,当计时器运行完毕时(如果它们没有被接收),它就会进入NACK列表。 接收方应该从ACK列表中发送5个左右的ACK以及每几秒钟一次的单个传输中的多达5个NACK。 如果发送方接收到这些消息并且有任何NACK,则应立即降低速度并在继续之前重新发送缺失的片段。已确认的数据可以从内存中释放。

祝你好运!


如果您想要高速的局域网通信,请禁用 Nagle 算法。由于大多数网络接口卡都提供分段的硬件加速,因此 TCP 通常仍然更快。 - Steve-o

4
我不确定具体的.Net实现情况,但UDP数据报通常受到链路MTU的限制,一般以1500为标准(IP头部和UDP头部共28字节)。UDP允许明确地丢弃和重新排列数据报,没有像TCP那样的流量控制。如果发送端超出套接字发送缓冲区,则网络堆栈将忽略随后的发送尝试,直到缓冲区空间再次可用(您需要检查send()的返回值)。编辑:我强烈建议使用TCP进行大文件传输。TCP提供了排序功能(您无需跟踪已丢失和重新排序的数据包),还具有先进的流量控制(因此快速发送方不会压倒慢速接收方),还可以进行路径MTU发现(即找到最佳数据分组并避免IP分段)。否则,您将不得不自己重新实现这些功能。

2
你是否看到网络上流动的IP片段?那就是CPU峰值 - 将64K数据报分段成MTU大小的数据包。 - Nikolai Fetissov
TCP/IP协议栈必须对您提供的64KB数据进行分段。这会导致CPU/网络负载的增加。 - Nikolai Fetissov
你认为为什么数据必须被分段?UDP支持多大的数据包?最大可以到64KB。 - raisyn
但是以太网不行。MTU 为1500字节(除非你在千兆链路上使用巨型帧,这样仍然可以提供约9000的数据量),所以发送机器必须将64KB的块分成更小的部分。您可以使用Wireshark或Microsoft提供的网络嗅探器轻松确认。 - Nikolai Fetissov
数据使用的大小是1472字节吗? - raisyn
显示剩余4条评论

2

我不想这么说,但你需要让线程休眠。你的吞吐量过载了。UDP不太适合无损数据传输。UDP是用于当你不介意丢失一些数据包时使用的。


除了丢失一些数据包,UDP甚至不能保证它们将按原始顺序接收,这也可能是一个问题。 - Lukas Pokorny
通常我会有最多10个相互依赖的UDP数据包...所以如果一个数据包丢失了,我也会丢掉其他9个数据包,如果数据包丢失了,这并不是问题。这就是为什么我不想使用TCP的原因...我还认为使用UDP可以获得更好的网络吞吐量。 - raisyn
加1..表示“UDP适用于您不介意丢失某些数据包”的情况。 - mahmoud nezar sarhan

0

可靠性-不,你不能用UDP实现它。

就我所了解的而言,这对于同时发送到多台计算机(广播)是有意义的。

在这种情况下,

  • 与它们中的每一个建立TCP连接,
  • 将数据分成块,
  • 为每个块分配ID,
  • 向具有TCP连接的每台计算机发送ID列表,
  • 使用UDP广播数据,
  • 通过TCP通知客户端数据传输已结束,
  • 然后客户端应该请求重新发送丢失的数据包

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接