Memra

InetAddress: resolving names and addresses

◈ 5 cards

The four InetAddress factory methods and why the class has no constructor, UnknownHostException as a checked failure, the JVM lookup cache and its short negative TTL, and why a reverse lookup fails silently.

No constructors, only factories

java.net.InetAddress is Java's representation of an IP address — v4 or v6 — and usually carries both a hostname and a numeric address. It has no public constructor, because building one may require talking to a DNS server, and a constructor that performs a network round trip is a bad constructor. You get instances from static factory methods instead:

  • getByName(String) — the common one. A name triggers a DNS lookup; a literal address string does not.
  • getAllByName(String) — the same lookup, returning every address the name maps to, as an array.
  • getLocalHost() — this machine. It tries DNS for a real name and address, and falls back to loopback when that fails.
  • getByAddress(byte[]) and getByAddress(String, byte[]) — build an address from raw bytes, with no DNS involved at all. These are the only ones that can produce an address for a host that does not exist; they throw only if the array is neither 4 nor 16 bytes long.

All of them declare UnknownHostException, which is checked and extends IOException. You will handle it on every lookup you ever write.

The lookup is a network call, and it is cached

getByName("www.example.com") is not a string assignment. It contacts the local DNS resolver and may wait seconds for an answer that has to traverse several servers. Because that is expensive, InetAddress caches successful lookups for the life of the JVM by default. Failures are cached too, but only for about ten seconds — a first attempt often times out just as the answer arrives, and the retry then succeeds. Both durations are controlled by the system properties networkaddress.cache.ttl and networkaddress.cache.negative.ttl, where -1 means never expire.

Budget accordingly: a program doing thousands of distinct lookups serially spends nearly all of its life blocked on the network, which is precisely the problem A1 solves with a thread pool.

Forward and reverse

A forward lookup turns a name into addresses. A reverse lookup turns an address into a name, and it is a different query against different records (PTR) that many address owners never publish. When you call getByName("208.201.239.100") no lookup happens at all — the object is built from the literal, and its hostname is set to that same string. The reverse query is deferred until you ask for the name.

And here is the trap: if the reverse lookup fails, getHostName() returns the numeric string you supplied. Success and failure are indistinguishable from the return value.

Worked example — one name, several addresses, one exception

public static void main(String[] args) {
    String host = args.length > 0 ? args[0] : "www.athabascau.ca";
    try {
        InetAddress[] all = InetAddress.getAllByName(host);
        System.out.println(host + " resolves to " + all.length + " address(es)");
        for (InetAddress a : all) {
            System.out.println("  " + a.getHostAddress());
        }
    } catch (UnknownHostException ex) {
        System.err.println("cannot resolve " + host);
    }
}

Two facts land immediately. The count is often greater than one, so "the address of a host" was never a well-formed idea — getByName would have picked one of them for you and never mentioned the rest. And feed it a name that does not exist: the program prints a single line and exits cleanly, because the compiler forced you to notice that a lookup can fail.

Run the same lookup twice in one process and the second call returns without touching the network — that is the JVM-lifetime cache, not luck. Do it with a name that does not resolve and the second attempt may well go out again, because the negative cache expires in about ten seconds.

That loop is the seed of A1: replace the hard-coded host with the client address parsed from each line of a web server log, and you have a log analyser. Its only problem will be speed, and module 3 fixes that. What you do with each address once you hold it — name it, classify it, compare it — is the next lesson.

factory methodDNS lookup?returnsgetByName(String)yes, for a nameone InetAddressgetAllByName(String)yes, for a nameInetAddress[]getLocalHost()yes, then falls backthis host, or loopbackgetByAddress(byte[])neveran address from bytesAll four declare UnknownHostException.
The middle column is the cost column. Only a hostname buys a network round trip; a literal address string is merely parsed, and getByAddress never consults DNS at all — which is why it is the one factory that will happily hand you an address for a host that does not exist.
NORMAL ~/memra/learn/comp-348/inetaddress-lookups-and-dns utf-8 LF