UdpClient - 有限的缓冲区大小?

Posted

技术标签:

【中文标题】UdpClient - 有限的缓冲区大小?【英文标题】:UdpClient -- limited buffersize? 【发布时间】:2011-05-26 06:27:27 【问题描述】:

我在使用 C# 中的 UdpClient 时遇到问题。我正在两个客户端之间通过 Internet 流式传输音频。

在我的麦克风上,采样率为 16khz,我发送带有音频的 UDP 数据包,每个数据包 6400 字节。这些永远不会通过,除了最后一个数据包,自从我关闭录音以来,它通常在 1200-3400 左右。 当我将采样率降低到 8khz 时,我会发送 3200 字节有效负载的数据包。由于某种原因,这些总是通过。

所以基本上任何高于 3200 的东西都会被搞砸(还没有测试过确切的数字,但是......)这到底是为什么?我在想 UdpClient 内部缓冲区可能太小还是什么?由于我经常发送流式音频数据包。

接收:

private void audioReceive(IAsyncResult asyn)
    
        try
        
            byte[] temp = audiosock.EndReceive(asyn, ref this.serverEP);
            this.waveProvider.AddSamples(temp, 0, temp.Length);

            this.textbox_display.Text = this.textbox_display.Text + " got bytes: " + temp.Length;
            audioSock.BeginReceive(new AsyncCallback(audioReceive), null);

        
        catch (Exception ez)
        
            MessageBox.Show("audioReceive: " + this.textbox_nick.Text + "        " +ez.ToString());
        

    

我找不到任何明显的错误。 (函数的 asyn 对象是 null 顺便说一句,我不需要使用 stateobject ,但这不应该与此相关)

我知道 UDP 不可靠,但考虑到每个 3200 大小的数据包都能通过,而且没有 6400 大小的数据包对我来说很可疑,尤其是最大大小是多少,64kb?

有什么想法吗?

【问题讨论】:

【参考方案1】:

超过 MTU(我认为大约 1500 字节)的数据包可能会被丢弃。例如,see this。听起来您可能会遇到这种情况。为了让它在不同的环境中更可靠地工作,最好将每个数据包的发送最大化为 1472 字节(以允许数据包开销),然后在接收端重新组合它们。

或者也许只是使用 TCP/IP。即使有些损失是可以接受的,但要使“简单”的 UDP 解决方案工作起来可能相当复杂。我正在开发一个支持 UDP 和 TCP/IP 通信的产品,并且(有根据的猜测)UDP 实现可能涉及 10 倍的代码并且具有更大的复杂性。当然,在我们的情况下,没有数据丢失是可以接受的,因此会有所改变。

【讨论】:

由于流量是通过互联网传输的,这听起来像是正在发生的事情。 为了扩展这一点,大于 MTU 的 IP 数据包将被分段。如果所有的分片都到达目的地,它们将被IP层重新组装成原始的IP数据包(包含原始的UDP数据报)。如果它们没有全部到达,UDP 中没有请求重传的机制,所以整个数据报都会丢失。【参考方案2】:

使用 IPv4 可以保证 576 字节(UDP 有效负载为 548),但对于大多数用户而言,至少应保持在 1472 字节(1444 UDP)以下。

您可以使用此处描述的 ping 测试 MTU 大小的工作原理,

http://help.expedient.net/broadband/mtu_ping_test.shtml

libjingle 使用 1280 字节的安全默认值(1252 UDP/IPv4、1232 UDP/IPv6),这与 IPv6 的保证最小值相匹配,

http://code.google.com/p/libjingle/source/browse/branches/nextsnap/talk/session/tunnel/pseudotcpchannel.cc?spec=svn17&r=13

【讨论】:

【参考方案3】:

自 2014 年以来,此链接可能是此问题的最佳答案:

UdpClient class .NET Reference source.

private const int MaxUDPSize = 0x10000;  
...
private byte[] m_Buffer = new byte[MaxUDPSize];

【讨论】:

以上是关于UdpClient - 有限的缓冲区大小?的主要内容,如果未能解决你的问题,请参考以下文章

并发那些事生产者消费者问题

linux IPC机制学习博客

等待 UDP 接收时我的计时器缓冲区会溢出吗?

生产者消费者模式

linux 有名管道(FIFO)

DPDK — RING(librte_ring,Ring Manager,环缓冲区管理组件)