DatagramChannel 在线发送丢失

DatagramChannel Send Missing On Wire

我发现我正在开发的工具中的数据报通道偶尔会丢失一些数据。 UDP 是这里要求的一部分,所以我主要只是想解决我所看到的行为。该工具是根据 Java 7(另一个要求)开发的,但我看到该行为发生的计算机是 运行,在 Java 8 JRE 上。

我有一个装饰器 class 用一些额外的行为装饰对 DatagramChannel.send 的调用,但调用实际上归结为:

public int send( ByteBuffer buffer, SocketAddress target ) throws 
{
    // some additional decorating code that can't be shared follows

    int bytesToWrite = buffer.remaining();
    int bytesWritten = decoratedChannel.send(buffer, target);

    if (bytesWritten != bytesToWrite) {
        // log the occurrence
        return bytesWritten;
    }
}

在此之上还有一点额外的装饰,它执行我们自己的碎片(作为远程主机要求的一部分)。因此,源数据始终保证最多为 1000 字节(完全在以太网帧的限制内)。装饰通道还配置为阻塞 I/O.

我在极少数情况下看到的是,将调用此例程(以及 DatagramChannel 的发送方法),但在线路上看不到任何数据(使用 Wireshark 进行监控)。发送例程总是 returns 在这种情况下也应该写入的字节数(因此 bytesWritten == bytesToWrite)。

我知道 UDP 存在可靠性问题(为此我们有自己的数据可靠性机制来解决数据丢失和其他问题),但我对数据报通道的实现行为感到好奇。如果发送 returning 写入的字节数,我至少应该在 Wireshark 中看到相应的帧吗?否则,我希望本机实现可能会抛出异常,或者至少不会 return 我期望写入的字节数?

实际上,我在 Wireshark 中进行了更多调整,最终发现了原因。我无意中过滤掉了ARP请求,这似乎是问题的原因,如this answer中所述:

ARP queues only one outbound IP datagram for a specified destination address while that IP address is being resolved to a MAC address. If a UDP-based application sends multiple IP datagrams to a single destination address without any pauses between them, some of the datagrams may be dropped if there is no ARP cache entry already present. An application can compensate for this by calling the Iphlpapi.dll routine SendArp() to establish an ARP cache entry, before sending the stream of packets.

ARP 条目似乎很快就会过时,偶尔的 ARP 请求会导致数据包丢失。我增加了 PC 接口的 ARP 超时,现在丢包的发生频率大大降低。