【问题标题】:Java DatagramPacket (UDP) maximum send/recv buffer sizeJava DatagramPacket (UDP) 最大发送/接收缓冲区大小
【发布时间】:2022-01-31 08:40:19
【问题描述】:

在 Java 中使用 DatagramPacket 时假设您有一个 byte[1024*1024] 缓冲区。如果您只是在发送/接收时为 DatagramPacket 传递它,那么 Java 会接收 DatagramPacket 块的调用,直到它读取整个兆字节?

我在问 Java 是否会将它拆分,或者只是尝试发送整个被丢弃的东西。

通常情况下,UDP 数据包的大小限制约为 64KB,但我想知道 Java 的 API 是否允许字节数组,如果这是一个限制,并且超大的东西会被丢弃或拆分并为您重新组装。

如果它被丢弃,哪个 API 调用会告诉我可以在 Java 调用中使用的最大数据负载?我听说 IPv6 也有巨型帧,但是 DatagramPacket(或 DatagramSocket)是否支持它,因为 UDP 定义了标头规范?

【问题讨论】:

    标签: java udp


    【解决方案1】:

    DatagramPacket 只是基于 UDP 的套接字的包装器,因此适用通常的 UDP 规则。

    64 KB 是完整 IP 数据报的理论最大大小,但只能保证路由 576 字节。在任何给定的网络路径上,具有最小最大传输单元的链路将确定实际限制。 (1500 字节,较少的标头是常见的最大值,但无法预测会有多少标头,因此将消息限制在 1400 字节左右是最安全的。)

    如果您超过 MTU 限制,IPv4 会自动将数据报分解成片段并在最后重新组合它们,但最多只能达到 64 KB,并且只有在所有片段都能通过的情况下。如果任何片段丢失,或者任何设备决定它不喜欢片段,那么整个数据包都会丢失。

    如上所述,不可能事先知道路径的 MTU 是多少。有多种算法可供尝试找出答案,但许多设备没有正确实施(或故意忽略)必要的标准,所以这一切都归结为反复试验。或者您可以只猜测每条消息 1400 个字节。

    至于错误,如果您尝试发送的字节数超过操作系统配置允许的字节数,您应该会收到EMSGSIZE 错误或其等效错误。如果您发送的数量少于该数量但超出网络允许的数量,则该数据包将消失。

    【讨论】:

    • 实际上,跨网络 IPv4 的最低保证 MTU 仅为 68 字节 - 576 是主机需要处理的最小值。无论哪种方式,这么小的 MTU 都非常非常不寻常。
    • 这是否意味着如果您的数据包大小大于 64KB,您将使用不同的协议?
    • @PhaniRahul:我会说它的意思是“感谢上帝,协议透明地处理分段并将我的数据分成所需数量的数据包”。我怀疑是否有任何实际使用的协议会给你更大的数据包大小。 :)
    • 仅供参考:IPv6 数据包的最小 MTU:1280
    • @lxgr 根据 RFC 1122,最小值为 576。“主机”包括路由器。
    【解决方案2】:

    java.net.DatagramPacket 缓冲区最大大小为 65507。

    https://en.wikipedia.org/wiki/User_Datagram_Protocol#UDP_datagram_structure

    最大传输单元 (MTU) 大小因实现而异,但可以说与基本问题“Java DatagramPacket (UDP) 最大发送/接收缓冲区大小”无关,因为 MTU 对 java.net.DatagramPacket 层是透明的。

    【讨论】:

      【解决方案3】:

      @米海丹尼拉。因为我无法对上述答案添加评论,所以写到回复部分。

      继续您对 MTU 大小的回答,在我的实践中,我尝试使用 NetworkInterface.getMTU()-40 来设置 DatagramSocket.setSendBufferSize() 的缓冲区大小。所以,尽量不要依赖getSendBufferSize() 这是为了确保它在不同平台上匹配不同的窗口大小,并且在以太网上是普遍接受的(暂时忽略拨号)。我没有将它硬编码为 1460 字节(1500-20-20),因为在 Windows 上,MTU 大小普遍为 1500。但是,Windows 平台自己的窗口大小是 8192 字节,但我相信,通过将 SO_SNDBUF 设置为

      同样,对于接收缓冲区,我最多使用 64K 或 65535 字节。这样我的程序可以在使用不同窗口大小的不同平台上移植。

      你觉得这听起来不错吗?我没有实施任何工具来衡量任何差异,但假设它是基于现有的情况。

      【讨论】:

      • 设置小的缓冲区大小没有意义。您根本没有“减轻网络 IP 层的负担”或“减少一些延迟”。把它设置大,或者如果你不知道自己在做什么,就不要管它。但请确保您不要发送任何太大的东西。 UDP 中没有“窗口大小”。你是说 MTU 吗?
      • @EJP。网络上有很多帖子明确提到碎片会增加网络/路由器的开销。以pedrotrigueira.net/?page_id=163 为例。通过设置 SO_SNDBUF
      • 通过设置SO_SNDBUF <= MTU,您可以阻止自己发送更大的数据报,但您也可以阻止 UDP 缓冲传出数据报,即使它们的大小是可接受的,从而过度阻止您的发送代码. send() 的大小决定了数据报的大小,你应该保持 that SO_SNDBUF 有多大。我对任意引用 3rd 方博客不太感兴趣,但你的博客没有提到 SO_SNDBUF,所以它不支持你的情况。
      • @EJP,我发布了第 3 方的链接只是为了让您知道,即使您通过应用程序(因此是应用程序层)发送大型 UDP 数据包,然后,基于窗口大小(例如,Windows 有一个 8192 字节),它将以这种形式传递给 IP 层,然后 IP 层会将其分段为 1480 字节,每个 IP 数据包大小具有 IP 标头中的公共 ID、分段偏移量等。由于当今大多数网络使用以太网,MTU
      • @EJP。继续我上面的评论......所以,即使 UDP 不知道数据包在交付给应用程序之前是否被分段,数据包也经历了许多跃点,因此有许多碎片和 rassemblies。这增加了网络的开销,因此,发送方的数据包大小对于时间敏感的应用程序的整体效率确实很重要。现在,您不必向第 3 方阅读此内容,您可以转到 IP /UDP rfcs 以获得更多说明。这对 TCP 无关紧要,因为它是一个流协议,并且 1 字节在应用层是可以的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-10
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-23
      相关资源
      最近更新 更多