Java DatagramPacket(UDP)发送/接收缓冲区的最大大小

20
在Java中使用DatagramPacket时,假设您有一个byte[1024*1024]缓冲区。 如果您只是将其传递给DatagramPacket进行发送/接收,那么Java接收调用DatagramPacket时是否会阻塞直到读取整个兆字节?
我想知道Java是否会将其拆分或尝试发送整个被丢弃的内容。
通常,UDP数据包的大小限制约为64KB,但我想知道由于Java的API允许使用字节数组,因此是否存在限制,以及是否会丢弃超大的内容并为您拆分和重新组装。
如果它被丢弃,哪个API调用会告诉我可以在Java调用中使用的最大数据负载?我听说IPv6也有巨型帧,但是由于UDP定义了头规范,DatagramPacket(或DatagramSocket)是否支持它?
3个回答

29

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

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

如果超过MTU限制,IPv4将自动将数据报拆分为片段,并在结束时重新组合它们,但仅限于64千字节,并且仅在所有片段都通过时才会这样做。如果任何片段丢失或任何设备决定不喜欢片段,则整个数据包将丢失。

如上所述,事先无法知道路径的MTU是多少。有各种算法可供试验以查明,但许多设备未正确实现(或故意忽略)必要的标准,因此一切都归结为试错。或者你可以猜测每条消息的大小约为1400字节。

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


1
实际上,IPv4网络中的最小保证MTU仅为68字节 - 要求主机处理的最小值为576。无论如何,这样小的MTU都非常不寻常。 - lxgr
这是否意味着如果您的数据包大小大于64KB,您将使用不同的协议? - Phani Rahul
@PhaniRahul:我认为这意味着“感谢上帝,协议透明地处理了分段并将我的数据转换为所需的所有数据包”。我怀疑任何实际使用的协议都不会给你更大的数据包大小。 :) - Mihai Danila
FYI:IPv6数据包的最小MTU为1280。 - Ferrybig
@lxgr 根据RFC 1122,最小值为576。 “主机”包括路由器。 - user207421
@PhaniRahul - 说实话,比 MTU 大得多的 UDP 消息并不实用。鉴于数据包丢失的概率为 P,请计算出一个大型 UDP 消息中一个或多个 N 个数据包丢失的概率。(提示:搜索生日悖论。) - Stephen C

0

-1

@ Mihai Danila。因为我无法在上面的答案中添加评论,所以写到回复部分。

关于MTU大小的问题,根据我的实践,我尝试使用NetworkInterface.getMTU()-40来设置DatagramSocket.setSendBufferSize()的缓冲区大小。因此,我尽量不依赖于getSendBufferSize()。这是为了确保它与不同平台上的不同窗口大小匹配,并且在以太网上是普遍可接受的(暂时忽略拨号)。我没有将其硬编码为1460字节(1500-20-20),因为在Windows上,MTU大小普遍为1500。但是,Windows平台自己的窗口大小为8192字节,但我相信,通过将SO_SNDBUF设置为< MTU,我可以减轻网络/IP层的负担,并为所有路由器和接收器的跳跃提供一些开销。从而减少网络延迟。

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

你觉得这样听起来可以吗?我还没有实现任何测量差异的工具,但是根据已有的情况假设是这样的。


@EJP。网络/路由器的碎片化会增加开销,网上有很多帖子明确提到这一点。以http://pedrotrigueira.net/?page_id=163为例。通过设置SO_SNDBUF的大小<= MTU,您可以避免碎片化和重组的开销。您是正确的,UDP在传输层不必处理平台窗口大小,但如果数据包大于平台的窗口大小,则会被截断传递到传输层。因此,您无法发送64K数据包。 - Ashley
1
通过设置 SO_SNDBUF <= MTU,您防止自己发送任何更大的数据报,但也阻止了 UDP 缓冲传出的数据报,即使它们是可接受的大小,并且不必要地阻塞了您的发送代码。它是由 send() 的大小来确定数据报的大小,您应该保持 send() 的大小小于 MTU。如果您不发送太大的数据报,那么无论 SO_SNDBUF 多大,它们都不会太大。我对第三方博客并不感兴趣,因为它们并不能支持您的观点,而您的博客也没有提到 SO_SNDBUF - user207421
@EJP,我发布了第三方链接只是为了让您知道,即使通过您的应用程序发送大型UDP数据包(因此是应用层),基于窗口大小(例如,Windows有8192字节),它将以该形式传递到IP层,然后将其分成1480字节的每个IP数据包大小,具有公共ID、片偏移等在IP头中。由于今天大多数网络使用以太网,MTU < 1500,这些片段中的许多到达路由器时是无序的,然后路由器进行组装并进一步发送到目标,目标再次进行重组。 - Ashley
@EJP。继续我上面的评论...即使UDP不知道数据包在传递到应用程序之前是否已经被分段,但是该数据包经过了许多跳,因此也经历了许多分段和重组。这增加了网络开销,因此发送方的数据包大小对于时间敏感的应用程序的整体效率非常重要。现在,您无需去第三方阅读此内容,可以查看IP / UDP rfcs以获取更多澄清。对于TCP来说这并不重要,因为它是一种流协议,在应用层1字节就足够了。 - Ashley
@EJP,在大多数情况下,您的程序可以正常工作,但在网络上效率相对较低。因此,最好使用大小小于MTU的最佳实践。我已经在我的评论中提到了SO_SNDBUF。 - Ashley
显示剩余3条评论

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