如何调试数据包丢失?

7
我编写了一个C++应用程序(在Linux上运行),它提供大约400 kbps的RTP流。对于大多数目标,这很好用,但是有些目标会出现数据包丢失的情况。这些有问题的目标似乎都有一种共同点,就是连接速度较慢,但应该足够快来接收我发送的流。
由于这些目标可以接收其他应用程序发送的类似RTP流而没有数据包丢失,我的应用程序可能存在问题。
我已经验证了一些事情: - 在tcpdump中,我看到所有的RTP数据包都从发送机器发出 - 有一个UDP发送缓冲区(我尝试了64KB和300KB之间的大小) - RTP数据包大多数情况下保持在1400字节以下,以避免分段
发送应用程序可以采取什么措施来最小化数据包丢失的可能性,并且最好的调试方法是什么?
5个回答

10

不要以大批突发数据包的形式发送数据。

数据包丢失通常是由于速度较慢的路由器具有有限的数据包缓冲区大小所造成的。如果慢速路由器在接收到另外10个数据包之前有时间发送10个数据包,那么它可能可以很好地处理1 Mbps 的数据传输。但是,如果100 Mbps 的发送端向其发送了50个数据包,它除了要丢弃其中的40个数据包外别无选择。

尝试分散发送的时间,每次只写入必要的内容。如果您需要每五分之一秒写入一个数据包,请采用这种方式而不是每秒写入5个数据包。


6

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测试。这可能会检测到路由中的慢跳。在两台机器上运行它以检查与第二台机器的连接。


1
这里有一些好的建议,但我不确定它是否会对他有所帮助。实际的数据包丢失可能发生在他无法看到统计信息的ISP路由器上。 - Zan Lynx
实际上,我在发送机器上使用netstat并没有看到任何数据包丢失。不幸的是,到达目的地的路径涉及很多我无法直接访问的网络设备。 - Gene Vincent
mtr的输出看起来非常有趣,但似乎没有触发与我的应用程序相同的数据包丢失。 - Gene Vincent

4

RTP通常使用本质上易丢失的UDP。数据包可能会在发送方和接收方之间任何地方丢失,因此本地调试将对您毫无用处。

明显的事情:

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

如果其他方法都失败了,WireShark是您的朋友。它将为您提供应用程序发送多少数据以及何时发送数据的真实图片。


一个非常小的UDP发送缓冲区不会意味着只要稍微有一点延迟,数据包就会在发送机器上自动丢失吗? - Gene Vincent
@Gene - 这是极不可能的。虽然UDP不能保证数据包被接收,但它应该确保以某种形式发送了数据包。而且如果没有发送,netstat 会显示出来。[当你说“UDP缓冲区”时,你具体指的是什么?我认为UDP通常不会进行缓冲...] - Roddy
每个套接字(包括UDP套接字)都有一个发送缓冲区,数据存储在其中,直到网络堆栈将其发送出去。应用程序可以使用setsockopt(SO_SNDBUF)来影响此缓冲区的大小。当缓冲区已满时,TCP发送例程会阻塞,而UDP则会被丢弃。 - Gene Vincent
@Gene,根据W.Richard Stevens的说法,UDP发送缓冲区仅确定可发送的数据报的最大大小。它不会缓冲多个数据报。 - Roddy
数据报没有大小限制...它可以达到1MB。 它将被分割成数据包大小,然后进行处理。 - kumar

0
你应该尝试降低发送数据包的速率。连接慢可能意味着各种问题,而试图以高速率发送大小不同的数据包并不会有所帮助。

-3

这可能不是你想要的答案,但如果我遇到数据包丢失的问题,我会尝试将我的应用程序切换为使用TCP,并消除大部分数据包丢失的担忧。


RTP 的许多重点是利用 UDP 语义;特别是允许丢失数据包而不会使其余的流程停滞。 - jesup
翻译:糟糕!我对 RTP 一无所知,我的错。我现在会去了解它。感谢提醒! - Carl Smotricz

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