Dynamically find other hosts in a LAN in Java - java

A while ago I developed a little LAN chat app. in Java which allows chatting with other hosts, send images, etc. Although it was created just for fun, now it's being used where I work.
Currently, there is no "chat server" on the app. where each client registers, updates it's status, etc. (I liked the idea of symmetric design and not depending on a server running on some other machine).
Instead, each host is a client/server which has a hosts.properties file with the hostname of the other hosts, and - for instance - broadcasts to each one of them when sending a massive message/image/whatever.
In the beginning there were just a couple of hosts, so this hosts.properties file wasn't an issue. But as the amount of users increased, the need of updating that file was a bit daunting. So now I've decided to get rid of it, and each time the app. starts, dynammically find the other active hosts.
However, I cannot find the correct way of implement this. I've tried starting different threads, each one of them searching for other hosts in a known range of IP addresses. Something like this (simplified for the sake of readability):
/** HostsLocator */
public static void searchForHosts(boolean waitToEnd) {
for (int i=0; i < MAX_IP; i+= MAX_IP / threads) {
HostsLocator detector = new HostsLocator(i, i+(MAX_IP / threads - 1)); // range: from - to
new Thread(detector).start();
}
}
public void run() {
for (int i=from; i<=to; i++)
findHosts( maskAddress + Integer.toString(i) );
}
public static boolean findHosts(String IP) {
InetAddress address = InetAddress.getByName(IP);
if ( address.isReachable(CONNECTION_TIME_OUT) )
// host found!
}
However:
With a single thread and a low value in CONNECTION_TIME_OUT (500ms) I get wrong Host Not Found status for for hosts actually active.
With a high value in CONNECTION_TIME_OUT (5000ms) and only one single thread takes forever to end
With several threads I've also found problems similar like the first one, due to collisions.
So... I guess there's a better way of solving this problem but I couldn't find it. Any advice? Thanks!

You could try UDP Broadcast to a specific port. All running instances of your app on the network could listen to that port and then respond with a message identifying them as a host.

You could do this a lot easier using UDP. Check this tutorial for examples.

Use Bonjour/Zeroconf.
The jmdns project has all you need.

For finding all hosts in lan in java execute commands from java and add the result to JList
Here is the small code that will help to you to read all hosts in lan in windows there will be other commands for other os take look at the following code
try {
Runtime rt = Runtime.getRuntime();
FileWriter write=new FileWriter("mylist.txt");
BufferedWriter writer=new BufferedWriter(write);
Process pr = rt.exec("net view");
BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line=null;
String hosts="";
while((line=input.readLine()) != null) {
Thread.sleep(100);
if((!(line.equals("")))&&(!(line.equalsIgnoreCase("Server Name Remark")))&&(!(line.equalsIgnoreCase("-------------------------------------------------------------------------------")))&&(!(line.equalsIgnoreCase("The command completed successfully."))))
{
line=line.replace('\\',' ');
line=line.trim();
listModel.addElement(line);
hosts=hosts+line.trim()+",";
hosts=hosts.trim();
}
}
writer.write(hosts);
writer.close();
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}

Each host keeps track of all the hosts they have met. When you shut down, save the known hosts to file and reuse the next time you start up.
Every so many minutes, send each of the known hosts a list of all known hosts.
That way
a) No network scanning
b) A new host will spread around the network
Then when a new host joins, he just needs to know 1 other host to learn about everyone.
A host that isn't seen for a week, or is seen from a new IP is dropped from the list of updated.

You could attempt to use DNS service discovery
There seems to be a project on sourceforge (that I have not looked at, beyond doing a cursory search...)

Related

How to get to know what ports are taken?

I am creating a simple learning project (chat using sockets) in Java and today I faced a problem. Maybe the point is an obvious one for somebody, but I am confused with it
The purpose
To get to know (at least one of the following):
A list of the currently opened free/taken ports on a PC
Whether the port I want to use is locked
What I tried
I've created a simple raw-project and run two ServerSocket on one port. In this case I have caught a java.net.BindException with notification that "...Address already in use: JVM_Bind...". But in this way I am able to check the port avaliability only if my JVM has captured it. In case if other program listens to the port, I do not know anything about it. I am adding a code below.
public class Main {
public static void main(String[] args) throws IOException {
MyThread myThread = new MyThread();
ServerSocket serverSocket = new ServerSocket(5940);
myThread.start();
serverSocket.accept();
}
}
public class MyThread extends Thread {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(5940);// exception is thrown here
serverSocket.accept();
} catch (IOException e) {
System.err.println("SECOND SERVER");
e.printStackTrace();
interrupt();
}
}
}
PS Any advice is warmly welcomed
I've created a simple raw-project and run two ServerSocket on one
port. In this case I have caught a java.net.BindException with
notification that "...Address already in use: JVM_Bind...". But in
this way I am able to check the port avaliability only if my JVM has
captured it. In case if other program listens to the port, I do not
know anything about it.
I think you're misinterpreting your result. I have every reason to believe that if the port you request is already bound by any process then your attempt to bind it will fail with a BindException. That takes care of
Whether the port I want to use is locked
. As for
A list of the currently opened free/taken ports on a PC
, there are system utilities that can get you that information, but it is useless to you. Whichever end initiates the connection (i.e. the client) needs to know in advance what port to try to connect to. It cannot get that from the server, because that presents a chicken & egg problem.
The usual approach is that the server listens to a specific port chosen by its developer or its admin, and that port number is provided to clients out of band -- often simply by it being a standard, well-known port number. That's how most of the basic network protocols work; for example, HTTP servers run on port 80 by default. If the wanted port happens to be unavailable when the server attempts to bind to it then that indicates a misconfiguration of the machine, and the server simply fails to start.
The client, on the other hand, does not need to choose a port number at all. The system will choose one for it automatically when it attempts to connect to the server.

Refresh ARP tables programmatically

I have been reading around the topic of getting a list of devices connected to my WIFI hotspot on my phone programmatically.
I found a useful post on stack overflow with the following code and a comment saying
This is incorrect as the ARP tables don't necessarily refresh when a
device disconnects. One say say, that you could simply ping all the
devices in the table to see which IPs are active but it is quite
possible that a device is firewalled to not respond to ICMP request
and your ping would fail. This solution, although a working one, isn't
robust and accurate.
I was wondering, if reading proc/net/arp isn't accurate enough due to refresh issues, how can you force the system to do a refresh to get accurate data?
private int countNumMac()
{
int macCount = 0;
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("/proc/net/arp"));
String line;
while ((line = br.readLine()) != null) {
String[] splitted = line.split(" +");
if (splitted != null && splitted.length >= 4) {
// Basic sanity check
String mac = splitted[3];
if (mac.matches("..:..:..:..:..:..")) {
macCount++;
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
br.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (macCount == 0)
return 0;
else
return macCount-1; //One MAC address entry will be for the host.
}
The ARP table is not a distributed list of "hosts that are online." It's a local-only list of "hosts that we've seen on this network."
Once you realize this, you'll note that there's no way of removing entries when someone disconnects other than trying to connect to them. Just have a continuous loop in the background, connecting to each host and sending a single ICMP packet (kinda hard to pull off from Java but Android does come with a ping command-line tool).
Granted, hosts that don't reply to ping will be filtered out but depending on the application that might be acceptable.
Alternatively, just let the user try to connect to any of the listed hosts and gracefully time out when the other party is offline. That's what most networking applications do anyway and is the only foolproof way of checking if the host is online.
Ping may often do its arp request and get arp replies from active hosts even if the icmp echo request is subsequently blocked. Therefore ping can in some cases be used to populate the arp table in order to check it for network presence even if icmp is being actively blocked.
But if this is not accurate enough or feels too crude, network presence can be mapped directly using the arp protocol and without involving protocols higher up in the stack which stand a higher risk of being blocked.
arping is the Linux utility commonly used for manual arp level operations (on Linux).
Here is the source code for arping.
Through quick-googling it appears there are utilities for Android which perform corresponding operations, I also found source code which seems to be for arping on Google Android BusyBox.
The arping utility may be usable as is, assuming of course you ensure its presence on your phone. Alternatively one or both of the code variants may serve as inspiration as to how the problem may be programmatically solved in your own code.

Receiving data of RS-232C device using java

I have recently purchased a USB Bar code scanner. It has 3 different interface selection options:
RS-232C
USB
Wand Emulation
The requirement is only to receive the scanned bar-code using RS-232C interface with the help of Java (Rxtx API).
So as far as I know, I will need a COM Port to be defined in RXTX to start interaction with the device
But the problem is I am not able to find out its COM Port while using in RS-232C interface.
Is there anything that I am missing while communicating a RS-232C port, How can I find the port number.
Please help me in this.
Update: As suggested I scanned my system for all the serial ports using the code below(using JSSC)
import jssc.SerialPortList;
public class Main {
public static void main(String[] args) {
String[] portNames = SerialPortList.getPortNames();
for(int i = 0; i < portNames.length; i++){
System.out.println(portNames[i]);
}
}
}
One thing to note: when I connect my barcode scanner and remove the scanner, there is no change in the port list obtained by the above code.
Output:
COM3
COM11
COM18
COM32
COM33
COM34
COM35
COM36
COM37
COM38
COM39
COM40
COM42
COM45
COM52
COM53
COM59
COM60
COM61
COM62
COM63
After the output I tried to listen each of the above port one by one using the following code:
import jssc.SerialPort;
import jssc.SerialPortException;
public class Main {
public static void main(String[] args) {
SerialPort serialPort = new SerialPort("COM63"); //manually setting all the ports above one by one
try {
serialPort.openPort();//Open serial port
byte[] buffer = serialPort.readBytes(10);
System.out.println(buffer.toString());
serialPort.closePort();//Close serial port
}
catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
I got either the port is busy or no output (In the meanwhile I kept on scanning using my barcode scanner)
Here's a solution posted elsewhere on StackOverflow. Basically you need to cycle your available comports from your OS and display/select the intended one. If you're having trouble with this please post some code for us to review.
I'm unfamiliar with those APIs, but fairly familiar with the electrical end of the COM port. There is no automatic "handshake" that indicates whether a device is attached or not, unlike a USB port. However, there are several status lines that are present in the interface.
In addition to the TD/RD signals (transmitted data/received data) there are RTS/CTS -- Request To Send and Clear To Send. RTS and CTS are such that they go "not ready" when nothing is connected.
The usual protocol is that the device asserts RTS and then the other end returns CTS to indicate that everything is ready. However, this is all complicated by the fact that the computer can appear as either a "device" or a "modem" (the only two things that RS-232 knows about). The result is that you can have several different configurations of pins and signals, depending on the assumed modes of the two pieces. (If you're lucky the scanner docs describe some of this.)
Further complicating things is that there are DSR/DTR signals -- Data Set (Modem) Ready and Data Terminal Ready. In most PC configurations these are ignored, but not always.
So, if you don't have luck soon with your scanning you may have to look at the pinouts and use a voltmeter and some jumpers to set you're physical port in a state that the scanner will find. Then there will be further experimentation to determine how to set up the status signals to get the scanner to talk.

java server to handle multiple tcp connections

im trying to write a simple web server in java.
right now ive only got a simple program but id like to extend it so that it can serve multiple browsers by establishing multiple tcp connections.
ive been reading about threading. my understanding is that you can make a new thread and that will continue as if its another program entirely. so with a new thread, it can be like there are 2 web servers which can serve 2 browsers, or x web servers which can serve x web browsers.
im a bit lost on how to create new threads in java though and to give each new thread a connection.
my thoughts are that i would have a loop like this which gets new connections and passes each new connection to a new thread
// make new ServerSocket
while (true) {
Socket newConn = serverSocket.accept();
// make new thread, and pass in newConn
}
can someone give me some guidance on how to move forward?
(also if ive made an error somewhere, please do point it out. im new to threaded programming so its entirely possible ive not properly understood it)
rob
edit:
k thanks all.
i went and wrote something, that java tutorial helped a lot.
ive got a new issue now
i added a loop in my run() method in the new thread which contains a 10 second countdown (using Thread.sleep(1000)) whenever the server receives a request for an image, so i can see which threads are running when. (index.html has 4 images in it)
so i requested the index.html page and my server works fine. then i opened up about a dozen new tabs. my expectation was that the request for the index.html page would be instant but it would take 10 seconds for the images to be sent to the browser (because of that delay i put in there), at which point the server would receive the request for the next index.html page, and so on. overall, i thought that the dozen index.html pages would be served instantly while it would take 10 seconds for the 4 * 12 = 36 images to be served on all tabs.
what actually happened was it took 10 seconds to get the first 4 images, then 10 seconds for the next 4 images, etc. so rather than serving multiple web pages, my server just queues up requests and deals with one page at a time.
i think my program is at fault. but i feel like i might not properly understand how a browser interacts with a server. i thought the browser requests new objects as the html page is parsed. so my server should be receiving dozens of requests if i open a dozen pages. i tried opening up several tabs in FF and then several windows in FF but this did not help.
HOWEVER, when i opened up IE, FF and Chrome, and i asked for index.html at different times (about 2 seconds apart), it looked like each browser was receiving the page simultaneously, in other words, at one point, there were 12 different images being served, 4 to each browser
so i guess im looking for a bit of confirmation that this is the expected behavior? and if so, why is it that i could only see this behavior when i opened up 3 different browsers and not when i opened up multiple tabs?
(for those that asked, i plan ok taking a networks course next year, but im trying to do some of the basic stuff now. so half self learning, half h/w)
If you are looking for something robust look online for a working solution.
If it is for learning purposes, then create your own.
There are several ways to do this. The easiest is to do this As taken from the Java Tutorial :
import java.net.*;
import java.io.*;
public class MultiServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening)
new MultiServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
import java.net.*;
import java.io.*;
public class MultiServerThread extends Thread {
private Socket socket = null;
public MultiServerThread(Socket socket) {
super("MultiServerThread");
this.socket = socket;
}
public void run() {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine, outputLine;
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye"))
break;
}
out.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
You would implement your logic for processing your requests in:
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
You could optimize your code by putting your Threads in a Thread Pool so you did not need to create a new Thread each time.
The part below is subjective and depends on the types of requests and what you do with each one.
If you have a lot of concurrent client requests then NIO is the way to go.
If your requests are short and you have over 10 concurrent ones create a pool.
If your requests are more than 100, then I would start looking at NIO.
You might also consider Netty and Java NIO. There's more than one way to do it.
Sun's classic Java tutorial includes a section on programming with sockets that walks you through an example very similar to the program you're trying to write.
a web server is nothing but a glorified socket server with messaging. tech has been around since the very first network connection was made. i had a project about a year and a half ago that was similar to what your trying to do. Java NIO is the best bet to start with, has connection and thread pooling and all the advanced stuff that a web server needs, but its a bit complicated. if you want a VERY good baseline to start with, check out http://www.quickserver.org/ the system i wrote was based on this and it now handles about 45,000 devices on one server last i heard.

Issues receiving in RXTX

I've been using RXTX for about a year now, without too many problems. I just started a new program to interact with a new piece of hardware, so I reused the connect() method I've used on my other projects, but I have a weird problem I've never seen before.
The Problem
The device works fine, because when I connect with HyperTerminal, I send things and receive what I expect, and Serial Port Monitor(SPM) reflects this.
However, when I run the simple HyperTerminal-clone I wrote to diagnose the problem I'm having with my main app, bytes are sent, according to SPM, but nothing is received, and my SerialPortEventListener never fires. Even when I check for available data in the main loop, reader.ready() returns false. If I ignore this check, then I get an exception, details below.
Relevant section of connect() method
// Configure and open port
port = (SerialPort) CommPortIdentifier.getPortIdentifier(name)
.open(owner,1000)
port.setSerialPortParams(baud, databits, stopbits, parity);
port.setFlowControlMode(fc_mode);
final BufferedReader br = new BufferedReader(
new InputStreamReader(
port.getInputStream(),
"US-ASCII"));
// Add listener to print received characters to screen
port.addEventListener(new SerialPortEventListener(){
public void serialEvent(SerialPortEvent ev) {
try {
System.out.println("Received: "+br.readLine());
} catch (IOException e) { e.printStackTrace(); }
}
});
port.notifyOnDataAvailable();
Exception
java.io.IOException: Underlying input stream returned zero bytes
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:268)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.read(BufferedReader.java:157)
at <my code>
The big question (again)
I think I've eliminated all possible hardware problems, so what could be wrong with my code, or the RXTX library?
Edit: something interesting
When I open HyperTerminal after sending a bunch of commands from java that should have gotten responses, all of the responses appear immediately, as if they had been put in the buffer somewhere, but unavailable.
Edit 2: Tried something new, same results
I ran the code example found here, with the same results. No data came in, but when I switched to a new program, it came all at once.
Edit 3
The hardware is fine, and even a different computer has the same problem. I am not using any sort of USB adapter.
I've started using PortMon, too, and it's giving me some interesting results. HyperTerminal and RXTX are not using the same settings, and RXTX always polls the port, unlike HyperTerminal, but I still can't see what settings would affect this. As soon as I can isolate the configuration from the constant polling, I'll post my PortMon logs.
Edit 4
Is it possible that some sort of Windows update in the last 3 months could have caused this? It has screwed up one of my MATLAB mex-based programs once.
Edit 5
I've also noticed some things that are different between HyperTerminal, RXTX, and a separate program I found that communicates with the device (but doesn't do what I want, which is why I'm rolling my own program)
HyperTerminal - set to no flow control, but Serial Port Monitor's RTS and DTR indicators are green
Other program - not sure what settings it thinks it's using, but only SPM's RTS indicator is green
RXTX - no matter what flow control I set, only SPM's CTS and DTR indicators are on.
From Serial Port Monitor's help files (paraphrased):
the indicators display the state of the serial control lines
RTS - Request To Send
CTS - Clear To Send
DTR - Data Terminal Ready
OK, sorry it's taken me so long to come back to this question. Here's how I got things working.
Note: This method will NOT work for everyone, please read below before copy/pasting into your own code
public void connect(CommPortIdentifier portId) throws Failure {
if (portId == null)
throw new Failure("No port set");
try { port = (SerialPort) portId.open(getClass().getName(), 10000); }
catch (PortInUseException e) {
throw new Failure("Port in use by " + e.currentOwner,e); }
try {
port.setSerialPortParams(9600, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
port.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN
| SerialPort.FLOWCONTROL_RTSCTS_OUT);
} catch (UnsupportedCommOperationException e) { throw new Failure(e); }
port.setRTS(true);
// More setup
}
So, in my case, the problem was that my particular device requires RTS flow control. Other devices may require different things (CTS, XON/XOFF), so check that device's manual. By default, RXTX disables all flow control mechanisms (unlike Hypertrm or other programs). Enabling each one is a two-step process.
Once you have a SerialPort object, call the setFlowControlMode() method, and bitwise-OR ('|') the necessary SerialPort.FLOWCONTROL_ constants
Set the appropriate flow control to true or false (like I did with port.setRTS(true))
For the others with similar problems, if this doesn't work, I suggest
Using a serial port monitoring program like Serial Port Monitor and/or PortMon (both Windows) to see what is actually going on.
Emailing the RXTX developers at rxtx#qbang.org (they are very helpful)
There is a simpler solution to this problem. This is what I did:
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while (keepRunning) {
try {
while ((br.ready()) && (line = br.readLine()) != null) {
....
}
If you check that the buffer "is ready" before you read it there should be no problem.
Ok, I do realize this thread is extremely old, but none of these solutions worked for me. I had the same problem and I tried everything to fix it, to no avail. Then I did some research on what causes the problem, and, when not dealing with Serial Communication, it happens at the end of a file. So, I figured I needed to add an ending to whatever is being received by the Java Application, specifically, a line return (\n). And sure enough, it fixed the problem for me! Hopefully this helps someone new, as I'm not expecting this to help anyone already on this thread...
(might be too simple, but might as well start somewhere...)
Is the port in use? Rather than:
port = (SerialPort) CommPortIdentifier.getPortIdentifier(name)
.open(owner,1000)
what about:
CommPortIdentifier portIdentifier;
try {
portIdentifier = CommPortIdentifier.getPortIdentifier(name);
} catch (NoSuchPortException nspe) {
// handle?
}
if (portIdentifier.isCurrentlyOwned()) {
// handle?
}
port = portIdentifier.open(owner, 1000);
if (!(port instanceof SerialPort)) {
// handle?
}
Are you swallowing any exceptions?
I tried RXTX a few months ago and ran into similar problems. I suggest two things:
Create a virtual comport using com0com. Enable trace logging. Compare the logs for when you use Hyperterminal versus when you run your own program. The difference will highlight what you are doing wrong.
In my humble opinion, RXTX's design is flawed and its implementation is quite buggy (take a look at its source-code, what a mess!). I've published an alternative library at http://kenai.com/projects/jperipheral with the following caveats: It's Windows-only and there are no pre-built binaries. Both of these will change in the near future. If you are interested in trying it out send me an email using http://desktopbeautifier.com/Main/contactus and I'll send you a pre-built version.
If anyone is still getting java.io.IOException: Underlying input stream returned zero bytes after you've read your characters using br.readline() for RXTX (even when you are checking first to see if br.readline() == null), just do this simple fix with a try/catch:
String line;
while (true){
try{
line = br.readLine();
}catch(IOException e){
System.out.println("No more characters received");
break;
}
//Print the line read
if (line.length() != 0)
System.out.println(line);
}
I've done some searching and it appears that this is the best/easiest way to get around this problem.
EDIT : I take that back. I tried this and still ended up having some problems. I'd recommend working with the raw InputStream directly, and implementing your own read/readLine method using InputStream.read(). That worked for me.

Categories

Resources