Windows 上的反向 dns 查找阻止无法解析的 IP 地址几秒钟

Rerverse dns lookups on Windows block for several seconds for unresolvable IP addresses

我正在使用 Java 的 InetAddress.getHostName() 执行一些反向 DNS 查找,但它所花费的时间似乎有问题。这是一个代码片段:

public static void main(String[] args) throws IOException {

byte[][] addresses = new byte[][] { { 10, (byte) 0, (byte) 0, (byte) 138 }
    , new byte[] { (byte) 216, (byte) 239, (byte) 49, (byte) 245 }
    ,{ 8, (byte) 8, (byte) 8, (byte) 8 } };

    for (byte[] addr : addresses) {
        InetAddress inet = InetAddress.getByAddress(addr);
        long before = System.currentTimeMillis();
        String hostName = inet.getHostName();
        System.out.printf("%20s %40s %5d\n", inet.getHostAddress(), hostName, (System.currentTimeMillis() - before));
    }
}

这是我机器上的输出:

    10.0.0.138                               10.0.0.138  4503
216.239.49.245                           216.239.49.245  4591
       8.8.8.8           google-public-dns-a.google.com     8

解析 10.0.0.138 和 216.239.49.245 各需要 4.5 秒,无论我 运行 此代码的次数如何。这似乎发生在所有无法解析的 IP 地址上。

这不是网络问题,因为根据 wireshark 捕获,当此代码为 运行 时,DNS 查询 甚至不会发送 除非先清除 DNS 缓存(然后结果会更慢 - 每次解析大约需要 4.7 秒)。

那么 OS 的本地 DNS 缓存实际上需要 Java 4.5 秒才能超时吗?这是没有意义的。这些 IP 地址的命令行实用程序 nslookup returns(无法解析)结果要快得多,它甚至不使用缓存!

有人可以解释这种行为并提出加快这些分辨率的方法吗?在不求助于外部库的情况下,我唯一能想到的就是使用多线程,因此至少 4.5 秒的超时将并行执行。

作为参考,我在 Windows 7 x64

上使用 JDK 7u71

编辑 1: This 问题似乎相关,但那里的答案说性能取决于网络,这不是我观察到的。

编辑2:

这似乎是一个 windows 问题。同一 LAN 中的一台机器使用完全相同的 DNS,运行ning OpenSuse 13.1 与 JDK 1.7u67 返回以下结果:

没有 DNS 缓存:

10.0.0.138                                   10.0.0.138  116             
216.239.49.245                           216.239.49.245  5098             
8.8.8.8                  google-public-dns-a.google.com  301

使用 DNS 缓存:

10.0.0.138                                   10.0.0.138  5
216.239.49.245                           216.239.49.245  9             
8.8.8.8                  google-public-dns-a.google.com  40

编辑3:

最终我不得不通过使用 dnsjava 进行自己的反向 DNS 查找来解决这个问题。

Windows 中的 DNS 客户端实施似乎存在问题。我刚刚在 C#.NET 中尝试了相同的逻辑:

 static void Main(string[] args)
    {
        byte[][] addresses = new byte[][] { new byte[] { 10, (byte) 0, (byte) 0, (byte) 138 },
            new byte[] { (byte) 216, (byte) 239, (byte) 49, (byte) 245 },
            new byte []{ 8, (byte) 8, (byte) 8, (byte) 8 } };
        foreach (byte[] addr in addresses)
        {
            IPAddress inet = new IPAddress(addr);
            DateTime before = DateTime.Now;
            String hostName = null;
            try
            {
                hostName = System.Net.Dns.GetHostByAddress(inet).HostName;
            }
            catch { }
            finally
            {
                DateTime after = DateTime.Now;
                Console.WriteLine("{0} {1} {2}", inet.ToString(), hostName!=null?hostName:"N/A", after.Subtract(before));
            }
        }
        Console.ReadLine();
    }

这些是结果:

   10.0.0.138 N/A 00:00:04.5604560
   216.239.49.245 N/A 00:00:04.7984798
   8.8.8.8 google-public-dns-a.google.com 00:00:00.0060006

有趣的是,在刷新 DNS 缓存后,Windows 将所有 DNS 请求发送到网络。 DNS 服务器在 0.25 秒后回复,但如果答案是 "No Such Name",DNS 客户端在整个超时期间仍会阻塞。