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)
no machine is called noMachine or has the IP 192.168.0.222 (always unreachable)
both machines are running Apache Tomcat on port 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 Internet
Occasionally, 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.
Not sure how practical this is.
How about doing the equivalent of traceroute(tracert on windows) and once you get a success, you can proceed.
In corporate networks, I've seen ICMP(ping) blocked by admins BUT usually, tracert still works. If you can figure out a quick way to do what tracert does, that should do the trick ?
Good luck!
My most recent solution depends using a TimedSocket (source code) with 3000ms timeout while performing a connect.
Timings:
1406ms : testLocalHost()
5280ms : testLAN()
Can't even get these to work properly:
testNoDNS()
testHaveDNS()
If you need to do this with a seriously large number of hosts in a very brief period of time, I'd consider using a tool like fping instead- shell out to exec it and parse the output when it comes back. fping runs a large number of parallel queries at once, so you could theoretically check a few thousand hosts in a minute (I think the limit is 4096?)
The rate determining step for host availability is not within your own code, but in the netlag. You must wait for the host to respond, and this can take time. If your program blocks while waiting for a response it could be a problem. I got around this by creating each host as an object, each with its own threaded method for checking availability. In my own situation I have 40 hosts I keep track of. My main program loops through an array of 40 machine objects once every 20 seconds, calling the appropriate method on each to check availability. Since each machine object spawns its own thread to do this, all 40 machines are interrogated concurrently and the (up to 500ms) response time for each isn't a problem.
Related
This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 2 years ago.
So I'm in the making of a very simple server/client complex using java. So far I have managed to figure out what happens if the client quits, because then the server receives null while listening from any input from the client.
BUT - what happens if the client is connected and the server quits for any reason... the server is supposed to wait for input from the client, but how can the client know that the server is not listening anymore? For me the clients call to the server just goes into the void... nothing happens...
Can I do something to find out when the server goes down? Time-out, ping/pong or something?
As You surely can see I'm quite new at this, I'm just curious. This was a puzzle for me ever since I attended computer science at the university.
Thanks in advance. dr_xemacs.
(I am assuming you are working with blocking server socket and socket and not with non blocking ones)
Similarly to the server, reading from streams of a closed connection will return null.
However if you instead do not want to rely on this or a scared that the connection to the server could somehow persist, you can also use time outs (check this out! ) which will throw SocketTimeoutException when the time is up and, to keep track of whether the server is up or not, create a ping/packet to assure server is still up and running.
Edit: I did a quick search and this could be useful to you! Take a look!
How can the client know that the server is not listening anymore?
If the client doesn't attempt to interact at some level with the service, it won't know.
Assuming that the client has sent a request, a few different scenarios.
If the service is no longer listening on the designated port, the client will typically get a "Connection Refused" exception.
If the service is still running (in a sense) but it is not working properly, then connection attempts from the client are likely to time out.
If the service's host is down, the client liable get a timeout.
If there are network connectivity or firewall issues, the client could get a timeout or some other exception.
Can I do something to find out when the server goes down? Time-out, ping/pong or something?
You attempt to connect and send a request. If it fails or times out, that means the service is down. If you are designing and implementing the service yourself, you could include a special "healthcheck" request for clients to "ping" on. But the flip-side is that network and server resources will be consumed in receiving and responding to these requests. It can affect your ability to scale up the number of clients, for example, if each client pings the service every N seconds.
But a client typically doesn't need to know whether the service is up or down. It typically only cares that service responds when it it sends a real request. And the simplest way to handle that is to just send the request and deal with the outcome. (The client code has to deal with all possible outcomes anyway when doing a real request. The service can go down, etc between the last healthcheck ping and when the client sends a real request.)
Bottom line: Don't bother with checking availability in the client unless the application (i.e. the end user) really needs to know.
Your Server probably may be running on a certain port and so you can add a health check at the client side and update a global flag with status to let client know about its availibity :-
Socket socket = null;
try
{
socket = new Socket(host, port);
return true;
}
catch (Exception e)
{
return false;
}
finally
{
if(socket != null)
try
{
socket.close();
}
catch(Exception e){}
}
I am currently using ch.ethz.ssh2.Connection to connect to my servers in java. sometimes it hangs on one server.(maybe like 10-15 seconds). I wanted to know what causes this hang time and how to avoid it.
Connection sample
conn = new ch.ethz.ssh2.Connection(serverName);
conn.connect();
boolean isAuthenticated = conn.authenticateWithPassword(user, pass);
logger.info("Connecting to " + server);
if (isAuthenticated == false) {
logger.info(server + " Please check credentials");
}
sess = conn.openSession();
// I am connecting to over 200 servers and closing them. What would be the best practice to loop thru all these servers in the minimal time.
//some servers quickly connects, while some takes some time.
why does this happen?
The main question is: Is it a code problem, a network problem or a server problem.
A code problem can be debugged - unfortunately ch.ethz.ssh2.Connection does not have any logging possibility to detect what is going inside.
May be you should thing about switching the ssh library (or use it for some tests with the problematic servers). From my experience sshj is very useful.
If it is a network problem or a server problem you can check what is going on via Wireshark. If network packets are sent but the response is delayed the problem is not the used client-side code.
My psychic debugging powers tell me that the server is doing a DNS lookup on the IP address of each client which connects. These DNS lookups are either taking a long time to complete, or they're failing entirely. The DNS lookup will block the authentication process until it finishes, successfully or not.
If the server is the OpenSSH server, this behavior is controlled by the sshd config "UseDNS" option.
I want to let the user have the freedom to choose a specific local address to connect to the target server since there might be customized routing policies, but want the program to pick up an ephemeral port instead of specifying one since that may need manual-test of local port availability.
I checked the constructors of "Socket" and "InetSocketAddress", it seems none of them have one to do the above task (even though it can pick up a local address and an ephemeral port simultaneously), and there is no method to do so after the initialization.
There is a construtor
public Socket(InetAddress address,
int port,
InetAddress localAddr,
int localPort)
throws IOException
that should be suitable for your requirement. If localPort is 0, the system will pick a free port.
You can create a Socket and call connect on it later.
Socket socket = new Socket(); // no idea where to connect
socket.connect(addressAndPort); // now I know.
What I do is have a TCPRegistry for testing purposes. This component takes care of aliased ports. e.g. host.port1. It gives it an ephemeral port on the server and allows the client to connect to it using the same string.
Note: to allow the client to start before the server I can ask it to pre-build these ServerSocket in the unit test.
Finally, at the end of the test, I can either check all Sockets and ServerSockets were closed, or forcefully clean them up.
It is designed for NIO, but could be adapted for plain IO TCPRegistry
In my application architecture I am having two database servers primary db and secondary db server (Replica server).
In my java code I am making a connection with DB to fetch some data now what I want is I will give the IP addresses of both DB servers in my code and will check which DB server is reachable and will connect with that only. But I am not getting how to implement it, the one way is try to telnet but not a good option because I want to disable the telnet on application server for some reasons.
Is there any other and best way to do this?
Personally, I would just attempt the connection (using standard database classes) and handle the exceptions if the connection fails.
Even if you confirm connectivity initially, nothing prevents a network problem occurring between that test and your actual attempt to use the database.
You can try pinging both hosts and use the one which responds. Here is a sample program.
InetAddress address = InetAddress.getByName("172.16.2.0");
// Try to reach the specified address within the timeout
// periode. If during this periode the address cannot be
// reach then the method returns false.
boolean reachable = address.isReachable(10000);
System.out.println("Is host reachable? " + reachable);
For a more elaborate program, see this Ping program example in Java.
Our application has server/client side. The client supports both offline and online work mode.
So I need to test the client when server down, regain connective.
Question comes. How to simulate server down. Use codes to switch from down to ready, or from ready to down state.
Thanks in advance.
Joseph
update:
Actually, I could not extend the server interface to response the incorrect status. In my test scenario, the server is transparent. So incorrect url + port is a solution to do this.
But I could not modify the url when the session is valid. Another method is modify the hosts file to do this. I have to face the privilege issue in Windows.
Depends on what you mean by "server down". Possible options are:
Write a fake/dummy server that can return error messages corresponding to being down for test purposes.
Change the IP address of the server that your client looks for to a non-existing one so that it will think that the server is entirely down.
The basic idea is to mock the behavior of your server somehow. You could use mocking frameworks to do so.
You could also create manual mocks for testing purposes. Let the "proxy" of the server on the client implement this interface:
public interface IServer
{
bool foo();
}
You could create a "fake" implementation of that server and return whatever you'd like
public class FakeOfflineServer implements IServer
{
public bool foo()
{
// throw some exception here.
}
}
This approach allows you to fake different scenarios (no network connectivity, invalid credentials, etc.)
You could also use composition to switch from up to down in your tests:
public bool FakeServer implements IServer
{
private IServer offline = new FakeOfflineServer();
private IServer online = new Server();
public bool isUp = false;
private IServer getServer()
{
return isUp ? online : offline;
}
public bool foo()
{
return getServer().foo();
}
}
While testing server down, give any incorrect URL OR Port (Prefered). For recovery give the correct URL/Port.
This depends where you are testing. If you're unit testing, the best option is the mocking suggested by Bryan Menard.
If you're testing in an integration or production environment, You can actually cut the connection between you and the server.
Depending upon your operating system, you can do this in a number of ways.
For Windows based systems, Fiddler is fantastic. You can simulate almost anything, including delays on the requests and indeed just throwing requests away. It does not require admin access for Windows.
For linux based systems, one technique I've used in the past is to use a proxy server, or cut the port at operating system level. You can do this using iptables for instance:
To deny access to a particular port (25 in this case)
/sbin/iptables -I OUTPUT -p tcp --dest 127.0.0.1 --dport 25 -j DROP
and to allow it again:
/sbin/iptables --delete OUTPUT 1
You'll need root acces for this to work, but it does have the advantage that you don't need to touch your server or client configuration.
To emulate the server down case, you could write a ServerAlwaysDown class extending your actual server, but throwing ServerException (HTTP 500) for every connection.
If you want to be thorough use always the closest you have to a production environment for the tests, put client and servers in different machines and cut the connection, then restore it.