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.
Related
I am using jssc for serial port communication with simulator which I made. The thing is whenever server requests for a device from my simulator I encounter a delay as device in my simulator replies after some time, not exactly after the request. For replying to the request packet I am using jssc method writeBytes() inside the serial event listener which is:
SerialPort.writeBytes(packet);
and the packet is less than 20 bytes and also I am checking my serial event that is
if(event.isRXCHAR() && event.getEventValue() > 0){}
Can you guys help me out to reduce this delay so that simulator device replies just after the request? Here is a piece of code-
public void serialEvent(SerialPortEvent event)
{
if(event.isRXCHAR() && event.getEventValue() > 0)
{
byte Server_PacketByte;
try {
Server_PacketByte = receiver_Port.readBytes(1)[0];
byte[] form_packet = PacketFormation(Server_PacketByte);// for adding bytes to make packet
if(form_packet == null)
{
return;
}
for(Device d : devices)
{
if(form_packet != null)
{
d.processPacket(form_packet);// in the list of devices I have all the information of device and also reply packet
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
inside processPacket()
if (packet.equals(REQUEST))
{
receiver_Port.writeBytes(device.getReply());
}
So, I think what's happening with your system is that the response from your simulator back to the server is taking too long, or the server requests are too close together to be useful. If your simulator's response to the server takes too long, then it may disregard or ignore your server's subsequent requests, and your server may handle this by either ignoring the response (since it's for a request it already gave up on) or worse, thinking the response to request #1 is the response to request #3 (which may have had different parameters, and would therefore be invalid).
The solution for this is to either have the server wait a longer amount of time for the response before trying another request, or to somehow reduce the amount of time the simulator needs to respond to the server's request.
If you're just doing an "is device connected" or "get device info"-style request of the device, or one that doesn't require real-time responses, you could have your simulator do that on its own (via a request loop on a separate thread or something) and cache the response, and just hand it back when requested from the server. However, you'd have to make sure that it gets aborted when a real-time request comes through, so it's almost more complicated than necessary.
EDIT: To clarify, I don't think that it's your serial communication that's experiencing an undue delay, because SERIAL COMMUNICATION IS SLOW. I think you haven't considered that fact in your design, and you're expecting all communication for your potentially large number of devices to complete within a certain time frame. In addition, each device may take a variable amount of time to deliver a response back over serial; some of these may not even have flow control implemented properly, resulting in occasional delays or, in rare cases, delivery failures.
You should have some other thread in your Simulator be requesting updates from devices periodically and storing them in a table. That way, when a request comes in from the Server that asks about all devices, their information is already there, and can be packaged and delivered back to the server without the need for serial communication.
I have seen that this question had been asked before in SO. Some of the threads are:
How to check if internet connection is present in java.
Detect internet Connection using Java.
Why does InetAddress.isReachable return false, when I can ping the IP address?.
All these threads are pretty old. The approaches that are defined there are:
Opening an HttpURLConnection by openConnection().
Checking InetAddress.isReachable.
Executing ping command through Process and processing the output.
I have seen if I use the second approach to check the connectivity with www.google.com then it is returning false, which should not be the result. But the first way works. I cannot use the last way since the respondent himself said it.
I have also seen the following way:
private boolean isConnected(Socket socket, String address) {
if(socket == null) {
throw new NullPointerException("Socket cannot be null");
}
try {
InetSocketAddress inetSocketAddress = new InetSocketAddress(address, 80);
socket.connect(inetSocketAddress);
return true;
} catch (Throwable cause) {
LOGGER.error(cause.getMessage(), cause);
return false;
}
}
By this way I am getting right output. The aforementioned threads mentioned that there is no proper way to validate if the computer is connected to the internet or not. But since these threads are old so I am hoping there might be some new way out there by which I can achieve what I want. Also I have to consider that there are various ways to access internet like LAN, Broadband, Dial Up, DSL etc and some server might block ping access or can block some IP.
Any pointer would be very helpful.
You could use the NetworkInterface class, it has a isUp() method which returns boolean indicating whether the particular interface is up and running (which could indicate if it's used for internet connection).
API: http://docs.oracle.com/javase/7/docs/api/java/net/NetworkInterface.html
I am looking for a bit of efficient code that can assist me in monitoring if a com port is still open using the RX/TX libraries.
Lets say I have a hardware device that communicates to the PC using a virtual com port and that device can be plugged in and out at any time. I want to show a connection status on the pc.
I have tried this with something like a buffered reader below and it registered that the device gets disconnected but I have to re-open the port from scratch in another method.
I am looking from something short like comPort.isOpen () or something?
// Set the value of is running
Start.isRunning = true;
// Check to see if the device is connected
while (Start.isRunning) {
// Try to connect to the device
try {
// Create a Buffered Reader
BufferedReader reader = new BufferedReader(
new InputStreamReader(serialPort.getInputStream()));
// Read the output
if (Character.toString((char) reader.read()).equalsIgnoreCase(
"^")) {
// Set the connected flag
Start.CONNECTED_FLAG = true;
// Set the connected fag
AddComponents.TFconnected.setText("Connected");
}
// Close the reader
reader.close();
// Let the thread sleep
Thread.sleep(500);
}
// Catch a error if the device is disconnected
catch (Exception err) {
// Set the connected flag
Start.CONNECTED_FLAG = false;
// Set the connected fag
AddComponents.TFconnected.setText("Disconnected");
// Let the thread sleep
Thread.sleep(500);
}
}
Disclaimer: Consider this a partial answer because I do not have intimate knowledge of the workings of serial ports, and my tests could not produce anything useful. Posting here regardless in the hopes any of this is helpful.
Unfortunately, as far as I know, there is no way to receive any kind of "connection / disconnection" event messages. Sadly, as I am not intimately familiar with the workings of serial ports, I cannot give you a full and proper explanation. However, from some research, one of the answers posted in that forum had this to say:
There's no event by the system to inform you of [a disconnection event] because that would require exclusive use of the COM port. If you have a SerialPort object created and have opened a port you should get a CDChanged when a devices is plugged in and unplugged from the serial port. That assumes the device follows the pins standards; not all devices do.
Note that the poster, and the link I've provided, are discussing this within the context of C#. However this seems to be related to how the ports work in general, regardless of language, so I am somewhat confident the same can be applied to RXTX Java.
There are some events you can attempt to listen for. In my tests I was only ever able to receive the DATA_AVAILABLE event, however my setup is a bit different (Raspberry PI) and I can't at the moment physically disconnect the device from the port, I can only attempt to block the device file (which may explain the failure of my test).
If you would like to attempt the event listening yourself, have your class implement SerialPortListener, register for the desired events, check the events in your serialEvent method. Here is an example:
public class YourClass implements SerialPortListener{
private SerialPort serialPort;
// ... serial port gets set up at some point ...
public void registerEvents(){
serialPort.addEventListener(this);
// listen to all the events
serialPort.notifyOnBreakInterrupt(true);
serialPort.notifyOnCarrierDetect(true);
serialPort.notifyOnCTS(true);
serialPort.notifyOnDataAvailable(true);
serialPort.notifyOnDSR(true);
serialPort.notifyOnFramingError(true);
serialPort.notifyOnOutputEmpty(true);
serialPort.notifyOnOverrunError(true);
serialPort.notifyOnParityError(true);
serialPort.notifyOnRingIndicator(true);
}
#Override
public void serialEvent(SerialPortEvent event) {
System.out.println("Received event. Type: " + event.getEventType() + ", old value: " + event.getOldValue() + ", new value: " + event.getNewValue());
}
}
If that ultimately fails, I believe the only other alternative is similar to your current solution; attempt to read from the port, and if it fails, consider it disconnected, and set your indicator accordingly. At each iteration, if it is disconnected, attempt to reconnect; if reconnect succeeds, reset your indicator to "connected".
Sorry I cannot be of more assistance. Hopefully some of that may lead to something useful.
Side Note:
If you want to DRY up your code slightly, put the Thread.sleep(500) in a finally block instead, since it appears to be executed regardless.
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...)
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.