【问题标题】:The most reliable and efficient udp packet size?最可靠和最有效的udp数据包大小?
【发布时间】:2023-04-10 09:11:01
【问题描述】:

通过 UDP 发送大量小数据包会占用更多资源(cpu、zlib 压缩等)。我读到here,通过 UDP 发送一个约 65kBYTE 的大数据包可能会失败,所以我认为发送大量较小的数据包会更频繁地成功,但随之而来的是使用更多处理能力的计算开销(或者至少是这样)我假设)。问题基本上是这样的;发送最大成功数据包并将计算降至最低的最佳方案是什么?是否有在大多数情况下都有效的特定尺寸?我将 Erlang 用于服务器,将 Enet 用于客户端(用 C++ 编写)。也使用 Zlib 压缩,我向每个客户端发送相同的数据包(我猜是广播术语)。

【问题讨论】:

    标签: udp processing-efficiency packet-loss


    【解决方案1】:

    534 字节。这需要在没有分段的情况下传输。当然,它仍然可以完全丢失。重传丢失数据包的开销和网络开销本身比任何 CPU 开销都要大几个数量级。

    【讨论】:

    • 我想知道分片对数据包的直接影响是什么。在我的应用程序中,当我从 508 转到 509 时,似乎在第二个数据包的末尾附加了一个 '\0'。我想知道它是取决于我的特定实现还是它是一个规则?
    • @mavErick 尾随的 null 来自您的代码,或者被您的代码错误地观察到。 UDP 不这样做。
    【解决方案2】:

    您可能使用了错误的协议。对于您关心传输的数据而言,UDP 几乎总是一个糟糕的选择。你在它上面完成了分层排序、重试和完整性逻辑,然后你就有了 TCP。

    【讨论】:

    • “重试”?但我认为这就是 tcp 的意义所在……重新发送数据包以完成工作。我这样做是为了一个在线游戏,所以 tcp 很可能会太慢,或者其他人都这么说。
    • “每个人”通常都是错误的。如果您担心数据可能无法到达,则需要 TCP。
    • 对于 TCP,您无需选择数据包大小。您只需将字节写入套接字的一端,它们就会从另一端出来。
    • 另一方面,如果您不关心数据包是否到达或它们到达的顺序(即大多数流数据协议),那么 UDP 是完美的选择。
    • 我在我的相机应用程序中使用 UDP 作为取景器。在这种情况下,UDP 是完美的。 TCP 是不必要的,而且速度很慢。您在实际项目中直接使用 TCP 多少次?也不多。可能主要使用 HTTP。
    【解决方案3】:

    UDP payload在大多数情况下不会导致ip碎片的最大大小是

    MTU size of the host handling the PDU (most of the case it will be 1500) -
    size of the IP header (20 bytes) -
    size of UDP header (8 bytes)
    
    1500 MTU - 20 IP hdr - 8 UDP hdr  = 1472 bytes
    

    @EJP 谈到了 534 字节,但我会将其修复为 508。这是FOR SURE不会造成碎片的字节数,因为主机可以设置的最小MTU大小是576IP header max size可以是60 bytes(508 = 576 MTU - 60 IP - 8 UDP)

    顺便说一句,我会尝试使用 1472 字节,因为 1500 是一个足够标准的值。

    如果您通过PPPoE 连接,请使用1492 而不是1500 进行计算。

    【讨论】:

    • 最小 IP MTU 为 576。它不包括以太网标头,因此实际上会给出 548。
    • 你是对的......我修复了计算,同时考虑到 IP 标头最大大小可以达到 60 字节
    • 1500这个数字从何而来?
    【解决方案4】:

    通过 UDP 发送大量小数据包会占用更多资源吗?

    是的,一定会的!我刚刚做了一个流媒体应用程序的实验。该应用程序每秒发送 2000 帧数据,时间精确。每帧的数据有效负载为 24 字节。我使用带有 sendto() 的 UDP 将此数据发送到另一个节点上的侦听器应用程序。

    我发现很有趣。这种程度的活动让我发送 CPU 崩溃了!我从大约 64% 的空闲 CPU 时间变成了大约 5%!这对我的应用程序来说是灾难性的,所以我必须解决这个问题。我决定尝试各种变化。

    首先,我简单地注释掉了 sendto() 调用,以查看数据包组装开销是什么样的。 CPU 时间减少了大约 1%。不错。好的...必须是 sendto() 调用!

    然后,我做了一个快速的 fakeout 测试...我在每 10 次迭代中只调用一次 sendto() API,但我将数据记录填充到之前长度的 10 倍,以模拟将一组较小的记录组合成一个较大的记录的效果,发送频率较低。结果相当令人满意:CPU 命中率为 7%,而之前为 59%。看起来,至少在我的 *NIX 类系统上,发送数据包的操作仅在调用开销方面是昂贵的。

    以防万一有人怀疑测试是否正常工作,我通过 Wireshark 观察实际 UDP 传输来验证所有结果,以确认一切正常。

    结论:它使用更少的 CPU 时间来减少发送较大数据包的频率,然后更频繁地以较小数据包的形式发送相同数量的数据。 诚然,我不知道如果UDP 开始破坏您过大的 UDP 数据报......我的意思是,我不知道这会增加多少 CPU 开销。我将尝试找出(我想了解自己)并更新此答案。

    【讨论】:

    • 我读过使用 sendo 而不是使用连接的 udp 套接字会产生一些开销,因为内核在 sendto 期间会临时连接套接字。如果您处于单播场景中,这根本不是问题。虽然我自己没有测试过,但是用连接的 udp 套接字测试你的场景会很有趣。来源:stackoverflow.com/a/638306/2298490
    猜你喜欢
    • 2020-05-25
    • 1970-01-01
    • 2011-10-07
    • 2015-05-17
    • 2020-06-23
    • 1970-01-01
    • 2010-09-21
    • 2011-02-18
    • 1970-01-01
    相关资源
    最近更新 更多