DatagramChannel发送丢失线路

时间:2015-02-17 19:20:11

标签: java udp arp

我正在开发的工具中看到一些数据报通道偶尔缺少数据。 UDP是这里要求的一部分,所以我主要是试图解决我所看到的行为。该工具是使用Java 7(另一个要求)开发的,但是我看到行为的计算机正在Java 8 JRE上运行。

我有一个装饰器类,用一些额外的行为来装饰对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的send方法)将被调用,但是在线上没有看到数据(用Wireshark监视)。 send例程总是返回本例中应该写入的字节数(所以bytesWritten == bytesToWrite)。

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

1 个答案:

答案 0 :(得分:1)

我实际上最终在Wireshark中更多地摆弄了原因。我无意中过滤掉了ARP请求,这似乎是导致问题的原因,如this answer中所述:

  

当该IP地址被解析为MAC地址时,ARP仅为指定的目标地址排队一个出站IP数据报。如果基于UDP的应用程序将多个IP数据报发送到单个目标地址而它们之间没有任何暂停,则如果不存在任何ARP缓存条目,则可能会丢弃某些数据报。应用程序可以通过在发送数据包流之前调用Iphlpapi.dll例程SendArp()来建立ARP缓存条目来补偿这一点。

看来ARP条目过时了,并且偶尔的ARP请求会导致丢弃的数据包。我增加了PC上接口的ARP超时,现在丢弃的数据包发生的频率要低得多。