Wednesday, November 04, 2009

Resolving domain names quickly with Java

Domain name resolution can take upward of 5 seconds depending on your ISP. Generally, when the resolution works, the DNS response comes back quickly, within a second. Any DNS entry not discovered within a second is likely to be dead.

Java provides InetAddress.getByName(domain) that does the DNS resolution for the given domain. There is no timeout you can specify to this function.

In the interest of providing a responsive user interface, as well as improve performance on background tasks, you can hack a timeout using a Thread. Feel free to re-use this code:

    public class DNSResolver implements Runnable {
private String domain;
private InetAddress inetAddr;

public DNSResolver(String domain) {
this.domain = domain;
}

public void run() {
try {
InetAddress addr = InetAddress.getByName(domain);
set(addr);
} catch (UnknownHostException e) {

}
}

public synchronized void set(InetAddress inetAddr) {
this.inetAddr = inetAddr;
}
public synchronized InetAddress get() {
return inetAddr;
}
}


Use this class as follows:

                DNSResolver dnsRes = new DNSResolver(host);
Thread t = new Thread(dnsRes);
t.start();
t.join(1000);
InetAddress inetAddr = dnsRes.get();



Basically, we start a thread that executes the blocking call to get the domain name. We wait for the thread to exit under 1 second (1000 ms). If the DNS resolution happens under a second, the thread will exit. If not, control will return to the main thread due to the 1000ms timeout. The thread will keep running, and eventually exit. But the main program has stopped caring at that point. It (main thread) will continue after 1 second considering the domain name to be unresolved.

Caveat:
Note that if you resolve a large number of domains that are unreachable, soon you will have lots of threads taking up memory and you could run out of JVM heap. So keep that in mind as you use this class.

Possible usage scenario:
If you are doing socket communication using nio, and you need to resolve DNS for each socket connection attached to the selector, it is important you quickly timeout DNS, as otherwise some sockets might get closed at the remote end. This is specially true for HTTP connections, if you connect to a HTTP server and do not send a request for a few seconds, the server will close the remote end of the socket.

5 comments:

CodeSith said...

Use a threadpool if you want to avoid using up too many threads. Take a look at Java5 thread libraries, there are a lot of goodies.

vitamin b said...

You must completely disable Java Permissions since clicking on High Safety will not prevent this vulnerability. If disabling Java is an unacceptable solution for you, then IE does offer more.

Anonymous said...

Thanks, good one

Andrew said...

I would love to use your function but dnsRes.get () always returns null.
What can be the reason?
Help me!!

DNSResolverBase dnsRes = new DNSResolverBase(url_server);
Thread t = new Thread(dnsRes);
t.start();
t.join(6000);
InetAddress inetAddr = dnsRes.get();

thushara said...

@Andrew: I suspect you are not passing something in url_server that INetAddress likes. Did you try using the INetAddress function directly first?