【问题标题】:How to debug packet loss?如何调试丢包?
【发布时间】:2011-02-12 23:58:50
【问题描述】:

我编写了一个 C++ 应用程序(在 Linux 上运行),它提供大约 400 kbps 的 RTP 流。对于大多数目的地来说,这可以正常工作,但有些目的地会出现数据包丢失。有问题的目的地似乎有一个共同的连接速度较慢,但​​对于我正在发送的流来说它应该足够快。

由于这些目的地能够为其他应用程序接收类似的 RTP 流而不会丢失数据包,因此我的应用程序可能有问题。

我已经验证了几件事: - 在 tcpdump 中,我看到所有 RTP 数据包都在发送机器上发出 - 有一个 UDP 发送缓冲区(我尝试了 64KB 和 300KB 之间的大小) - RTP 数据包大多保持在 1400 字节以下以避免碎片

发送应用程序可以做些什么来最大程度地减少数据包丢失的可能性以及调试这种情况的最佳方法是什么?

【问题讨论】:

    标签: c++ linux networking packet rtp


    【解决方案1】:

    RTP 通常使用UDP,它本质上是有损的。数据包可能会在发送方和接收方之间的任何地方丢失,因此本地调试不会显示任何有用的信息。

    要做的事情很明显:

    • a:降低整体数据速率
    • b:将“峰值”数据速率降低 更频繁地发送小数据包 而不是每隔几个就一大块 秒。即,减少您的 UDP 发送 缓冲区 - 甚至可能只有 1400 字节。
    • c: 看看是否可以切换到 TCP RTP 的变体。

    如果一切都失败了,WireShark 是你的朋友。它将让您真实了解应用程序发送了多少数据以及何时发送。

    【讨论】:

    • 一个非常小的 UDP 发送缓冲区是否意味着一旦发生最轻微的延迟,数据包就会在发送机器上自动丢失?
    • @Gene - 这是最不可能的。虽然 UDP 不保证接收到数据包,但它肯定应该保证数据包以某种形式“发送”。如果它没有被发送,netstat 会告诉你,我想。 [当您说“UDP 缓冲区”时,您究竟是什么意思?我认为 UDP 通常没有缓冲...?]
    • 每个套接字(这也适用于 UDP 套接字)都有一个发送缓冲区,其中存储数据,直到网络堆栈将其发送出去。应用程序可以使用 setsockopt(SO_SNDBUF) 影响此缓冲区的大小。当缓冲区已满时,TCP 发送例程阻塞并丢弃 UDP。
    • @Gene,根据 W.Richard Stevens 的说法,UDP 发送缓冲区只决定了可以发送的数据报的最大大小。它不缓冲多个数据报。
    • 数据报没有大小限制......它可以大到 1 MB。它将被分成数据包大小然后处理。
    【解决方案2】:

    netstat 有几个有用的选项来调试情况。

    第一个是netstat -su(转储UDP统计信息):

    dima@linux-z8mw:/media> netstat -su                                                      
    IcmpMsg:                                                                                 
        InType3: 679
        InType4: 20
        InType11: 548
        OutType3: 100
    Udp:
        12945 packets received
        88 packets to unknown port received.
        0 packet receive errors
        13139 packets sent
        RcvbufErrors: 0
        SndbufErrors: 0
    UdpLite:
        InDatagrams: 0
        NoPorts: 0
        InErrors: 0
        OutDatagrams: 0
        RcvbufErrors: 0
        SndbufErrors: 0
    IpExt:
        InNoRoutes: 0
        InTruncatedPkts: 0
        InMcastPkts: 3877
        OutMcastPkts: 3881
        InBcastPkts: 0
        OutBcastPkts: 0
        InOctets: 7172779304
        OutOctets: 785498393
        InMcastOctets: 525749
        OutMcastOctets: 525909
        InBcastOctets: 0
        OutBcastOctets: 0
    

    注意“RcvbufErrors”和“SndbufErrors”

    附加选项是监控进程的接收和发送UDP缓冲区:

    dima@linux-z8mw:/media> netstat -ua
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State
    udp        0      0 *:bootpc                *:*
    udp        0      0 *:40134                 *:*
    udp        0      0 *:737                   *:*
    udp        0      0 *:mdns                  *:*
    

    这里你需要查看你感兴趣的连接的Recv-Q和Send-Q列。如果值很高并且不降为零,则该进程无法处理负载。

    您可以在发送和接收机器上使用这些命令。

    您也可以使用 mtr,它结合了 traceroute 和 ping - 它对路由中的每个跃点进行 ping。 这可能会检测到您的路由中的慢跳。在其他机器上运行它以检查与第二台机器的连接。

    【讨论】:

    • 这里有一些很好的建议,但我不确定它会帮助他。实际的数据包丢失可能发生在他看不到统计信息的 ISP 路由器上。
    • 确实,我没有看到发送机器上的 netstat 有任何丢包。不幸的是,通往目的地的路径涉及很多我无法直接访问的网络设备。
    • mtr 输出看起来很有趣,但它似乎并没有像我的应用程序那样触发相同的丢包。
    【解决方案3】:

    不要以大块的突发块发送数据包。

    数据包丢失通常是由数据包缓冲区大小有限的慢速路由器引起的。如果慢速路由器有时间发送 10 个数据包,然后再接收 10 个数据包,它可能能够处理 1 Mbps,但如果 100 Mbps 发送方向它发送一大块 50 个数据包,它别无选择,只能丢弃其中 40 个。

    尝试分散发送,以便您只写在每个时间段内必须写的内容。如果您必须每五分之一秒写入一个数据包,请这样做,而不是每秒写入 5 个数据包。

    【讨论】:

      【解决方案4】:

      您应该尝试降低发送数据包的速率。缓慢的连接可能意味着各种各样的事情,尝试以高速率向它发送数据包(无论大小)都无济于事。

      【讨论】:

        【解决方案5】:

        这可能不是您想要的答案,但如果我遇到丢包问题,我会尝试将我的应用程序切换为使用 TCP,并且我不再担心丢包。

        【讨论】:

        • RTP 的主要目的是利用 UDP 语义;特别是允许丢失数据包而不会停止流的其余部分。
        • 糟糕!我对 RTP 的无知不好。我现在就去读一读。感谢您的提醒!
        猜你喜欢
        • 2015-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多