【问题标题】:DNS query freezes with DnsContextFactory in javaDNS 查询在 Java 中使用 DnsContextFactory 冻结
【发布时间】:2013-01-30 12:03:41
【问题描述】:

下面的程序执行 DNS 查找。除了主机名和 dns 的一种特定组合外,它运行良好:

import javax.naming.directory.InitialDirContext;
import javax.naming.NamingException;
import java.util.Hashtable;

public final class StackOverflow {
 public static void main(String args[]) throws NamingException {
  Hashtable<String, Object> env = new Hashtable<String, Object>();
  env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
  env.put("java.naming.provider.url", "dns://ns.dnssek.org");
  System.out.println(new InitialDirContext(env).getAttributes("dnsseccert.us", new String[]{"NS","A"}));
 }
}

我尝试设置超时:

env.put("com.sun.jndi.dns.timeout.initial", "220");

但是它的行为很奇怪。它有时在抛出时适用于小值:

DNS error [Root exception is java.net.SocketTimeoutException: Receive timed out];

但在大多数情况下,程序只是冻结并挂在内存中。

有其他人遇到过同样的问题并解决了吗?是否有任何其他设置我可以尝试阻止它?是否有其他替代方法 java.naming.factory.initial 我可以尝试?

【问题讨论】:

    标签: java dns nslookup


    【解决方案1】:

    我花了几个小时,但我终于找到了一个可以接受的解决方案。我下载了包 com.sun.jndi.dns 的源代码,并在 DnsClient 类中添加了一行:

    ...
    Tcp(InetAddress server, int port, int timeout) throws IOException {
        sock = new Socket(server, port);
        sock.setSoTimeout(timeout);  // <-- missing timeout
        sock.setTcpNoDelay(true);
        out = new java.io.BufferedOutputStream(sock.getOutputStream());
        in = new java.io.BufferedInputStream(sock.getInputStream());
    }
    ...
    

    我设置了套接字的超时。实际上,我还在 Tcp 构造函数中添加了一个参数并修改了它的调用,因此它现在由 com.sun.jndi.dns.timeout.initial 中的值初始化。

    【讨论】:

      【解决方案2】:

      请尝试同时设置com.sun.jndi.dns.timeout.initialcom.sun.jndi.dns.timeout.retries 值。例如,我看到以下一致的超时:

      $ cat StackOverflow.java 
      import javax.naming.directory.InitialDirContext;
      import javax.naming.NamingException;
      import java.util.Hashtable;
      
      public final class StackOverflow {
       public static void main(String args[]) throws NamingException {
        Hashtable<String, Object> env = new Hashtable<String, Object>();
        env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
        env.put("java.naming.provider.url", "dns://ns.dnssek.org");
      
        env.put("com.sun.jndi.dns.timeout.initial", "220");
        env.put("com.sun.jndi.dns.timeout.retries", "1");
      
        System.out.println(new InitialDirContext(env).getAttributes("dnsseccert.us", new String[]{"NS","A"}));
       }
      }
      

      $ java -version
      java version "11" 2018-09-25
      Java(TM) SE Runtime Environment 18.9 (build 11+28)
      Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11+28, mixed mode)
      

      $ java StackOverflow
      Exception in thread "main" javax.naming.CommunicationException: DNS error [Root exception is java.net.SocketTimeoutException: Receive timed out]; remaining name    'dnsseccert.us'
          at jdk.naming.dns/com.sun.jndi.dns.DnsClient.query(DnsClient.java:313)
          at jdk.naming.dns/com.sun.jndi.dns.Resolver.query(Resolver.java:81)
          at jdk.naming.dns/com.sun.jndi.dns.DnsContext.c_getAttributes(DnsContext.java:434)
          at java.naming/com.sun.jndi.toolkit.ctx.ComponentDirContext.p_getAttributes(ComponentDirContext.java:235)
          at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:141)
          at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:129)
          at java.naming/javax.naming.directory.InitialDirContext.getAttributes(InitialDirContext.java:142)
          at StackOverflow.main(StackOverflow.java:14)
          Caused by: java.net.SocketTimeoutException: Receive timed out
          at java.base/java.net.PlainDatagramSocketImpl.receive0(Native Method)
          at java.base/java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:181)
          at java.base/java.net.DatagramSocket.receive(DatagramSocket.java:814)
          at jdk.naming.dns/com.sun.jndi.dns.DnsClient.doUdpQuery(DnsClient.java:423)
          at jdk.naming.dns/com.sun.jndi.dns.DnsClient.query(DnsClient.java:212)
          ... 7 more
      

      您当然希望配置在您自己的环境中有意义的超时和重试值。以上数值仅用于演示目的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-22
        • 2014-07-18
        相关资源
        最近更新 更多