I have a server (java app running on my laptop) and a client (java app running on my android smartphone).
I'm trying to automatically find the IP address of the server from my client.
Right now i just loop all IPs in the same LAN (192.168.1.0 > 192.168.1.1.255) and if the server (that is listening on a custom port) accept the connection then i found the IP.
The problem is, if i set the connection timeout less then 200ms most of times the client can't find the server.
So the question is, how i can implement a better (faster) way to find the server IP?
I have tried the java InetAddress.isReachable() method but the server always seems unrechable...
And, if there isn't a better way, what do you think it's a good timeout value from local (LAN) socket connections?
Just for others... I just found a very good way to find the server IP in LESS THEN HALF SECOND!
here my solution:
String partialIp = "192.168.1.";
int port = 123;
int counter;
boolean found;
String ip;
Runnable tryNextIp = new Runnable() {
#Override
public void run() {
int myIp = counter++;
String targetIpTemp = partialIp + myIp;
Socket socketTemp = new Socket();
try {
socketTemp.connect(new InetSocketAddress(targetIpTemp, port), 6000);
socketTemp.close();
ip = targetIpTemp;
found = true;
} catch (IOException e) {
try {
socketTemp.close();
} catch (IOException e1) {}
}
}
};
String findIp() {
counter = 0;
found = false;
ExecutorService executorService = Executors.newFixedThreadPool(256);
for (int i=0; i<256; i++) {
if (found)
break;
executorService.execute(tryNextIp);
}
executorService.shutdown();
try {
while (!found && !executorService.isTerminated())
executorService.awaitTermination(200, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {}
if (found)
return ip;
else
return null;
}
A good timeout value is the time you're willing to wait for your server to reply, given typical network conditions and server response times. You need to pick a reasonable value, independently of your application here -- it is up to you to decide that if the server does not respond in X amount of time, then it is safe to assume it is not there.
To speed up your client, consider creating multiple threads to query multiple servers at once. Executors.newFixedThreadPool() will make this trivial for you.
However, you may want to consider other alternatives that don't require a full network scan; for example:
Just let the user/administrator specify the IP address (Why do you need to discover the server IP? Do you not know what machine you set up your server on? Why not just configure the server to have a static LAN IP?)
If you truly do need service discovery, technologies like NSD/Zeroconf/Bonjour allow for service advertising and discovery.
Even something very basic may be suitable to your needs, e.g. send a broadcast UDP packet from the client and let the server respond, or have the server periodically broadcast announcements.
What the socket timeout should be depends entirely on the expected service time of the request. Naively you could find the average service time and use double that for the timeout. If you want to get more accurate, you would need to plot the statistical distribution of service times, determine the standard deviation, and use the average plus three or even four times the standard deviation as the timeout, to make sure you don't get false-positive timeouts but you do detect failures within a reasonable time. Ultimately it depends on just how trigger-happy you want to be.
Related
I'm trying to see what IP's on a list are actually online. I'm currently using
public boolean IsOnline(String ip) {
try (Socket s = new Socket(ip, 80)) {
return true;
} catch (IOException ex) {
}
return false;
}
To check if the server is online. But it takes about 30 seconds for each IP to get checked. Is there a way to get faster results like another kind of method?
Not sure, but would INetAddress.isReachable suffice for your needs? You can't do ICMP messages in Java.
You may use the INetAddress.isReachable
".. A typical implementation will use ICMP ECHO REQUESTs if the
privilege can be obtained, otherwise it will try to establish a TCP
connection on port 7 (Echo) of the destination host..".
The only reason I can imagine, why this takes 30 seconds is, that nobody listens to port 80 and your socket connection timeout is 30 seconds. Please check for this by adding ex.printStackTrace() within the catch clause.
Please take a read here: Why are empty catch blocks a bad idea?
How you should "ping" a server, depends on what ports it is listening to. Normally INetAdresse.isReachable() works good. If your administrator blocks ICMP requests you may use the ssh port 22, to probe for the servers existence.
I have to make simultaneous tcp socket connections every x seconds to multiple machines, in order to get something like a status update packet.
I use a Callable thread class, which creates a future task that connects to each machine, sends a query packet, and receives a reply which is returned to the main thread that creates all the callable objects.
My socket connection class is :
public class ClientConnect implements Callable<String> {
Connection con = null;
Statement st = null;
ResultSet rs = null;
String hostipp, hostnamee;
ClientConnect(String hostname, String hostip) {
hostnamee=hostname;
hostipp = hostip;
}
#Override
public String call() throws Exception {
return GetData();
}
private String GetData() {
Socket so = new Socket();
SocketAddress sa = null;
PrintWriter out = null;
BufferedReader in = null;
try {
sa = new InetSocketAddress(InetAddress.getByName(hostipp), 2223);
} catch (UnknownHostException e1) {
e1.printStackTrace();
}
try {
so.connect(sa, 10000);
out = new PrintWriter(so.getOutputStream(), true);
out.println("\1IDC_UPDATE\1");
in = new BufferedReader(new InputStreamReader(so.getInputStream()));
String [] response = in.readLine().split("\1");
out.close();in.close();so.close(); so = null;
try{
Integer.parseInt(response[2]);
} catch(NumberFormatException e) {
System.out.println("Number format exception");
return hostnamee + "|-1" ;
}
return hostnamee + "|" + response[2];
} catch (IOException e) {
try {
if(out!=null)out.close();
if(in!=null)in.close();
so.close();so = null;
return hostnamee + "|-1" ;
} catch (IOException e1) {
// TODO Auto-generated catch block
return hostnamee + "|-1" ;
}
}
}
}
And this is the way i create a pool of threads in my main class :
private void StartThreadPool()
{
ExecutorService pool = Executors.newFixedThreadPool(30);
List<Future<String>> list = new ArrayList<Future<String>>();
for (Map.Entry<String, String> entry : pc_nameip.entrySet())
{
Callable<String> worker = new ClientConnect(entry.getKey(),entry.getValue());
Future<String> submit = pool.submit(worker);
list.add(submit);
}
for (Future<String> future : list) {
try {
String threadresult;
threadresult = future.get();
//........ PROCESS DATA HERE!..........//
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
The pc_nameip map contains (hostname, hostip) values and for every entry i create a ClientConnect thread object.
My problem is that when my list of machines contains lets say 10 pcs (which most of them are not alive), i get a lot of timeout exceptions (in alive pcs) even though my timeout limit is set to 10 seconds.
If i force the list to contain a single working pc, I have no problem.
The timeouts are pretty random, no clue what's causing them.
All machines are in a local network, the remote servers are written by my also (in C/C++) and been working in another setup for more than 2 years without any problems.
Am i missing something or could it be an os network restriction problem?
I am testing this code on windows xp sp3. Thanks in advance!
UPDATE:
After creating two new server machines, and keeping one that was getting a lot of timeouts, i have the following results :
For 100 thread runs over 20 minutes :
NEW_SERVER1 : 99 successful connections/ 1 timeouts
NEW_SERVER2 : 94 successful connections/ 6 timeouts
OLD_SERVER : 57 successful connections/ 43 timeouts
Other info :
- I experienced a JRE crash (EXCEPTION_ACCESS_VIOLATION (0xc0000005)) once and had to restart the application.
- I noticed that while the app was running my network connection was struggling as i was browsing the internet. I have no idea if this is expected but i think my having at MAX 15 threads is not that much.
So, fisrt of all my old servers had some kind of problem. No idea what that was, since my new servers were created from the same OS image.
Secondly, although the timeout percentage has dropped dramatically, i still think it is uncommon to get even one timeout in a small LAN like ours. But this could be a server's application part problem.
Finally my point of view is that, apart from the old server's problem (i still cannot beleive i lost so much time with that!), there must be either a server app bug, or a JDK related bug (since i experienced that JRE crash).
p.s. I use Eclipse as IDE and my JRE is the latest.
If any of the above ring any bells to you, please comment.
Thank you.
-----EDIT-----
Could it be that PrintWriter and/or BufferedReader are not actually thread safe????!!!?
----NEW EDIT 09 Sep 2013----
After re-reading all the comments and thanks to #Gray and his comment :
When you run multiple servers does the first couple work and the rest of them timeout? Might be interesting to put a small sleep in your fork loop (like 10 or 100ms) to see if it works that way.
I rearanged the tree list of the hosts/ip's and got some really strange results.
It seems that if an alive host is placed on top of the tree list, thus being first to start a socket connection, has no problem connecting and receiving packets without any delay or timeout.
On the contrary, if an alive host is placed at the bottom of the list, with several dead hosts before it, it just takes too long to connect and with my previous timeout of 10 secs it failed to connect. But after changing the timeout to 60 seconds (thanks to #EJP) i realised that no timeouts are occuring!
It just takes too long to connect (more than 20 seconds in some occasions).
Something is blobking new socket connections, and it isn't that the hosts or network is to busy to respond.
I have some debug data here, if you would like to take a look :
http://pastebin.com/2m8jDwKL
You could simply check for availability before you connect to the socket. There is an answer who provides some kind of hackish workaround https://stackoverflow.com/a/10145643/1809463
Process p1 = java.lang.Runtime.getRuntime().exec("ping -c 1 " + ip);
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
by jayunit100
It should work on unix and windows, since ping is a common program.
My problem is that when my list of machines contains lets say 10 pcs (which most of them are not alive), i get a lot of timeout exceptions (in alive pcs) even though my timeout limit is set to 10 seconds.
So as I understand the problem, if you have (for example) 10 PCs in your map and 1 is alive and the other 9 are not online, all 10 connections time out. If you just put the 1 alive PC in the map, it shows up as fine.
This points to some sort of concurrency problem but I can't see it. I would have thought that there was some sort of shared data that was not being locked or something. I see your test code is using Statement and ResultSet. Maybe there is a database connection that is being shared without locking or something? Can you try just returning the result string and printing it out?
Less likely is some sort of network or firewall configuration but the idea that one failed connection would cause another to fail is just strange. Maybe try running your program on one of the servers or from another computer?
If I try your test code, it seems to work fine. Here's the source code for my test class. It has no problems contacting a combination of online and offline hosts.
Lastly some quick comments about your code:
You should close the streams, readers, and sockets in a finally block. Check my test class for a better pattern there.
You should return a small Result class instead of passing back a String that they has to be parsed.
Hope this helps.
After a lot of reading and experimentation i will have to answer my own question (if i am allowed to do of course).
Java just can't handle concurrent multiple socket connections without adding a big performance overhead. At least in a Core2Duo/4GB RAM/ Windows XP machine.
Creating multiple concurrent socket connections to remote hosts (using of course the code i posted) creates some kind of resource bottleneck, or blocking situation, wich i am still not aware of.
If you try to connect to 20 hosts simultaneously, and a lot of them are disconnected, then you cannot guarantee a "fast" connection to the alive ones.
You will get connected but could be after 20-25 seconds. Meaning that you'll have to set socket timeout to something like 60 seconds. (not acceptable for my application)
If an alive host is lucky to start its connection try first (having in mind that concurrency is not absolute. the for loop still has sequentiality), then he will probably get connected very fast and get a response.
If it is unlucky, the socket.connect() method will block for some time, depending on how many are the hosts before it that will timeout eventually.
After adding a small sleep between the pool.submit(worker) method calls (100 ms) i realised that it makes some difference. I get to connect faster to the "unlucky" hosts. But still if the list of dead hosts is increased, the results are almost the same.
If i edit my host list and place a previously "unlucky" host at the top (before dead hosts), all problems dissapear...
So, for some reason the socket.connect() method creates a form of bottleneck when the hosts to connect to are many, and not alive. Be it a JVM problem, a OS limitation or bad coding from my side, i have no clue...
I will try a different coding approach and hopefully tommorow i will post some feedback.
p.s. This answer made me think of my problem :
https://stackoverflow.com/a/4351360/2025271
I am trying to make a app that scans all the ip in range for a specific open port (5050) and if it is open write some message on LOG.
heres the code :
public void run(){
for(int i=0;i<256;i++)
{
Log.d("NetworkScanner","attemping to contact 192.168.1."+i);
try {
Socket socket=new Socket(searchIP+i,5050);
possibleClients.add(searchIP);
socket.close();
Log.d("NetworkScanner"," 192.168.1."+i+" YEAAAHHH");
} catch (UnknownHostException e) {
Log.d("NetworkScanner"," 192.168.1."+i+" unavailable");
} catch (IOException e) {
e.printStackTrace();
}
}
}
EDIT: here's a new problem: Even if a host is found online without the port open the scanning process (for loop) is stuck for a long time before moving to next. also scanning each host is taking considerable time!
Phew the final solution was to make a Socket object with default constructor then create the InetAddr object for the host and then use the Connect(InetAddr,timeout) function of the socket api with timeout in milliseconds (approx 300ms) that scans every ip in just 300 ms or less (less than 200 ms may give errors) and multi threading to scan in parallel make it as fast as 5 sec to scan all the IPs in range..
You are breaking out of the loop when no Exception is thrown.
You need to remove break;
To address your new problem:
Of course it's slow. What did you expect? You are trying to establish a connection to each IP in your subnet which takes time. It seems you are only trying figure out what devices are available on the network, so you might be able to decrease the time a little by looking at this answer. He is using the build in isReachable method which accepts a timeout value. It will still take some time, but not that much time.
Remove the "break;"...it stops the iteration.
I want to find the IP address to a server on a local network in short time. I know the port that the application is using on the server.
I've tried this, but its too slow. Even when I know the IP, the responstime is too long (like 4 seconds or so for each IP). Considered this method, it would take minutes to scan the whole subnet from 10.0.0.0 to 10.0.0.255.
String ip = "10.0.0.45";
try {
InetAddress ping = InetAddress.getByName(ip);
Socket s = new Socket(ping, 32400);
System.out.println("Server found on IP: " + ping.getCanonicalHostName());
s.close();
} catch (IOException e) {
System.out.println("Nothing");
}
}
I could use threads, but that would still be slow. Ive seen application finding the IP in milliseconds out there. How do they do this? Java code would be appreciated!
You'll want to do two things - use threads to check many hosts simultaneously, and give the socket connection a lower timeout.
This answer show a very similar example.
I can suggest to look for source code of angry ip scanner. It is fast enough I think.
https://github.com/angryziber/ipscan
I want to find an open local port in some range.
How can I do that in the most efficient way, without connecting to the port.
If you want to find a local open port to bind a server to, then you can create a ServerSocket and if it does not throw an Exception, then it's open.
I did the following in one of my projects:
private int getAvailablePort() throws IOException {
int port = 0;
do {
port = RANDOM.get().nextInt(20000) + 10000;
} while (!isPortAvailable(port));
return port;
}
private boolean isPortAvailable(final int port) throws IOException {
ServerSocket ss = null;
try {
ss = new ServerSocket(port);
ss.setReuseAddress(true);
return true;
} catch (final IOException e) {
} finally {
if (ss != null) {
ss.close();
}
}
return false;
}
RANDOM is a ThreadLocal here, but of course you can do an incrementing part there.
There's a little problem you may face in a multitasking windows/unix environment: if some isPortAvailable(final int port) from any of the answers returns a true for you, that doesn't mean, that at the moment when you will actually bind it it still will be available. The better solution would be create a method
ServerSocket tryBind(int portRangeBegin, int portRangeEnd) throws UnableToBindException;
So that you will just launch it and receive open socket for you, on some available port in the given range.
If you mean port in a remote server, then you might need a library that support raw-socket to send a sync packet and wait for sync-ack packet, just like nmap does.
One way to do is use some native network command and parse the output.
You can try netstat command as its available on Windows and *nix platforms.
Typical command would be netstat -n
Its output is of following format.
you need to parse the 'Foreign Address column for localhost or 127.0.0.1' and get a list of busy ports. Then see if they are in the range you specified.
If this is not about port-sniffing, but about service discovery, consider using a rendez-vous server (like an RMI server) or using the UDP protocol. Back in the day we used JXTA for this, but I hope there is a better alternative for this now.
Essentially the same idea as Karaszi, but instead of constructing that many sockets, use the InetSocketAddress and try to bind a ServerSocket to every address in range, until you hit an open one.
If you don't want to bind to that port (although if you don't, the socket may as well be bound the next moment after you check), use a plain Socket Object and try to connect to the ports - if it works, the port is taken, if it doesn't (and you don't have a firewall forbiding the connection), then it's most likely free.
Just pass zero as the port number to new ServerSocket(), then it will find one for you. But you can forget about the range, it will choose from the system-defined range.