I would like the fastest and most accurate function boolean isReachable(String host, int port)
that passes the following JUnit tests under the conditions below. Timeout values are specified by the JUnit test itself, and may be considered "unreachable."
Please note: All answers must be platform-independent. This means that InetAddress.isReachable(int timeout)
is not going to work, since it relies on port 7
to do a ping on Windows (ICMP ping being an undocumented function on Windows), and this port is blocked in this setup.
LAN Setup:
thisMachine
(192.168.0.100
)otherMachine
(192.168.0.200
)noMachine
or has the IP 192.168.0.222
(always unreachable)8080
; all other ports are unreachable (including port 7
)example.com
(208.77.188.166
) is running a webserver on port 80
and is only reachable when the LAN is connected to the InternetOccasionally, the LAN is disconnected from the Internet in which case only local machines called by IP address are reachable (all others are unreachable; there's no DNS).
All tests are run on thisMachine
.
@Test(timeout=1600) // ~320ms per call (should be possible to do better)
public void testLocalhost() {
// We can always reach ourselves.
assertTrue(isReachable("localhost", 8080));
assertTrue(isReachable("127.0.0.1", 8080));
assertTrue(isReachable("thisMachine", 8080)); // Even if there's no DNS!
assertTrue(isReachable("192.168.0.100", 8080));
assertFalse(isReachable("localhost", 80)); // Nothing on that port.
}
@Test(timeout=5500) // ~1867ms per call (should be able to do better)
public void testLAN() {
assertTrue(isReachable("192.168.0.200", 8080)); // Always connected to the LAN.
assertFalse(isReachable("192.168.0.222", 8080)); // No such a machine.
assertFalse(isReachable("noMachine", 8080)); // No such machine.
}
The following test is only run when the LAN is disconnected from the Internet.
@Test(timeout=5600) // ~1867ms per call (reasonable?)
public void testNoDNS() {
assertFalse(isReachable("otherMachine", 8080)); // No DNS.
assertFalse(isReachable("example.com", 80)); // No DNS & no Internet.
assertFalse(isReachable("208.77.188.166", 80)); // No Internet.
}
The following test is only run when the LAN is connected to the Internet.
@Test(timeout=5600) // ~1867ms per call (reasonable?)
public void testHaveDNS() {
assertTrue(isReachable("otherMachine", 8080)); // DNS resolves local names.
assertTrue(isReachable("example.com", 80)); // DNS available.
assertTrue(isReachable("208.77.188.166", 80)); // Internet available.
}
Firstly you need to recognise that you have potentially conflicting requirements; IP sockets are not time deterministic. The quickest you can ever detect unreachability is after your elapsed timeout. You can only detect reachability quicker.
Assuming reachability/isReachable is your real objective, you should just use a straightforward non-blocking socket IO as shown in the Java Ping simulator, the example connects to the time service but would work equally well on 8080.
If you want to test whether you can connect to a web server you could also create a URL based on the host name and the port number and use that to create a URLConnection checking the result (including exceptions) of the connect method should tell you whether the webserver is reachable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With