Identify the kind of network interface - java

Having a java.net.NetworkInterface, is it possible to know the kind of interface we're dealing with (Wi-Fi, Ethernet, etc...)?
UPDATE
BTW: I'm on a Mac, and on a mac, NetworkInterface.getDisplayName() give "en0", "en1", "lo0", etc... (same as getName())

using the code from:
How to Determine Internet Network Interface in Java
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
OUTER : for (NetworkInterface interface_ : Collections.list(interfaces)) {
// we shouldn't care about loopback addresses
if (interface_.isLoopback())
continue;
// if you don't expect the interface to be up you can skip this
// though it would question the usability of the rest of the code
if (!interface_.isUp())
continue;
// iterate over the addresses associated with the interface
Enumeration<InetAddress> addresses = interface_.getInetAddresses();
for (InetAddress address : Collections.list(addresses)) {
// look only for ipv4 addresses
if (address instanceof Inet6Address)
continue;
// use a timeout big enough for your needs
if (!address.isReachable(3000))
continue;
// java 7's try-with-resources statement, so that
// we close the socket immediately after use
try (SocketChannel socket = SocketChannel.open()) {
// again, use a big enough timeout
socket.socket().setSoTimeout(3000);
// bind the socket to your local interface
socket.bind(new InetSocketAddress(address, 8080));
// try to connect to *somewhere*
socket.connect(new InetSocketAddress("google.com", 80));
} catch (IOException ex) {
ex.printStackTrace();
continue;
}
System.out.format("ni: %s, ia: %s\n", interface_, address);
// stops at the first *working* solution
break OUTER;
}
}

Related

Some doubts about how to retrieve multiple IP addresses (if I have more than one network card) in Java?

I have the following 2 problems in retrieving the ip of a client.
I have create the following code inside a class:
private static InetAddress thisIp;
static{
try {
thisIp = InetAddress.getLocalHost();
System.out.println("MyIp is: " + thisIp);
} catch(UnknownHostException ex) {
}
}
My problems are:
1) The previous code should retrieve the IP address of a client, when I execute it it print the following message:
MyIp is: andrea-virtual-machine/127.0.1.1
Why it begin with andrea-virtual-machine/ ? (I am developing on a virtual machine), is it a problem?
2) In this way I can retrieve only a single IP address but I could have more than a single network card so I could have more than a single IP address but multiple IP addresses
What can I do to handle this situation? I want put all the multiple IP addresses into an ArrayList
Tnx
Andrea
No, it's not a problem, it's simply an output that consists of hostname and IP (hostname/ip). A detail that you might want to read up: The method toString() in the class InetAddress is implemented to return this format.
The following code will list all IP addresses for each of the interfaces in your system (and also stores them in a list that you could then pass on etc...):
public static void main(String[] args) throws InterruptedException, IOException
{
List<String> allIps = new ArrayList<String>();
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
while (e.hasMoreElements())
{
NetworkInterface n = e.nextElement();
System.out.println(n.getName());
Enumeration<InetAddress> ee = n.getInetAddresses();
while (ee.hasMoreElements())
{
InetAddress i = ee.nextElement();
System.out.println(i.getHostAddress());
allIps.add(i.getHostAddress());
}
}
}
The method boolean isLoopbackAddress() allows you to filter the potentially unwanted loopback addresses.
The returned InetAddress is either a Inet4Address or a Inet6Address, using the instanceof you can figure out if the returned IP is IPv4 or IPv6 format.
if your system is configured with multiple ip then do like this.
try {
InetAddress inet = InetAddress.getLocalHost();
InetAddress[] ips = InetAddress.getAllByName(inet.getCanonicalHostName());
if (ips != null ) {
for (int i = 0; i < ips.length; i++) {
System.out.println(ips[i]);
}
}
} catch (UnknownHostException e) {
}
The hostname listed before the IP, incidentally, is part of INetAddress. You get both the name and the address because you didn't try to show only the address.

BufferedReader skipping random characters when reading from USB

I'm using a BufferedReader to read data from an USB gateway which periodically receives ZigBee network frames from an Arduino device.
This is what the frame is supposed to look like:
~f�}3�#v<-,R#}3�#v<--mac:0013A20040763C2D -H:-25.80 -T:22.58 -L:2.6451 -N:100.00 -D:0.0290 -B:35
But instead, it's always missing some characters near the end of the MAC address, like so:
~f�}3�#v<-,R#}3�#v<--mac:0013A2004076D -H:-25.80 -T:22.58 -L:2.6451 -N:100.00 -D:0.0290 -B:35
Or
~f�}3�#v<-,R#}3�#v<--mac:0013A2004076C2:-25.80 -T:22.58 -L:2.6451 -N:100.00 -D:0.0290 -B:35
The garbage at the beginning is low-level network header info, I guess.
I'm on Ubuntu, and the frames show perfectly fine when reading from a terminal, using
cat /dev/ttyUSB0
The code I use to read from the USB port looks like this. It runs in its own Thread.
public void run() {
Boolean keepRunning = true;
BufferedReader br = new BufferedReader(new InputStreamReader(portReader.getInputStream()));
String line;
while (keepRunning) {
try {
while ((line = br.readLine()) != null) {
handleData(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I'm using RXTXcomm.jar, available here http://rxtx.qbang.org/wiki/index.php/Main_Page
This is where I open the port.
while (!connected && !timedOut) {
System.out.print("\n\nConnecting to " + portName);
//Open Ports
CommPort commPort = portIdentifier.open(this.getClass()
.getName(), 9600);
//TODO Should we rule out other kinds?
if (commPort instanceof SerialPort) {
//Pass the open port
SerialPort serialPort = (SerialPort) commPort;
serialPort.enableReceiveTimeout(15000);
//Configure the port communication interface
serialPort.setSerialPortParams(bauds,
SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
//Open a stream and read from the port
inputStream = serialPort.getInputStream();
int portBuffer = inputStream.read();
//Check if there is something in the buffer, which
//means that a connection was established
if (portBuffer > -1) {
connected = true;
} else {
System.err.println("Connection to " + portName
+ " timed out");
serialPort.close();
inputStream.close();
timedOut = true;
}
} else {
System.err
.println("Error: Only serial ports are handled by this application.");
}
}
Any ideas on what could be going wrong?
well, I'm not sure if that was the problem, but you shouldn't cat on the serial port char device, as it won't setup the serial device properly (with the correct speed reading, parity etc.. and unbuffered). Always use instead screen /dev/ttyUSB0 SPEED, or python -m serial.tools.miniterm or minicom.
The garbage you're talking about that you prints out is indeed the frame data. You can find in the XBee manuals how it is built (the ~ character marking the beginning of a new frame in API mode, followed by the frame type, length, content and CRC). Given the CRC you can check whether the frame is correctly read, if there are no missing bits.
I wrote a XBee datagram parser in C++:
https://github.com/guyzmo/polluxnzcity/blob/master/PolluxGateway/src/xbee/xbee_communicator.C
and participated in one in C:
https://github.com/guyzmo/xbee-comm/blob/master/src/lib/xb_buffer.c
that you may use for inspiration to get things right.
And finally, I had really often contacts problems between the XBee and the board (making all incoming datagrams erroneous etc..). You may want to power cycle and/or replug the xbee dongle each time the data is getting wrong (hence the need of checking the incoming datagrams).

DatagramChannel.close() keeps port open on Windows

I'm implementing a Discover process that:
Open a UDP socket to listen for broadcast response on a given port
Send some requests (and expect later response)
Close the UDP socket after a given period of time
The first call works. But other call get a bind error. Address already in use: bind
I'm running Windows 7. I did some tests and found that after a channel.close(); Netstat still gives:
netstat -a -b -sp udp | grep 55224
UDP 0.0.0.0:55224 :
So the udp port is still opened at the OS level
I searched the web and it may be a leak at the os level : Some java Datagram Socket questions
I ran 2 tests one using NIO channel and one without (from a test found on the web). I reproduce my error with the NIO version but it works if I don`t use NIO.
I anybody can point me how I can make it works with NIO. The targetted platform is Android where I dont want to always listen for broadcast but only for repetitive period of time.
TEST SOCKET
public void testConnectCloseWithSocket() {
long tCumulative = 0;
int errAt = -1;
System.out.println("start...");
for (int i = 0; i < 4000; i++) {
try {
errAt = i;
DatagramSocket result = new DatagramSocket(null);
result.bind(new InetSocketAddress(InetAddress.getLocalHost(), 9005));
result.close();
//success at last
tCumulative = 0;
} catch (Exception e) {
System.out.println("Error (at="+errAt+") (waited="+tCumulative+"ms): " + e.getMessage());
tCumulative+=50;
try {
Thread.sleep(50);
} catch (InterruptedException e1) {
}
i--;
}
}
System.out.println("end...");
}
RESULT SOCKET<
start...
Error (at=1319) (waited=0ms): Address already in use: Cannot bind
Error (at=1438) (waited=0ms): Address already in use: Cannot bind
Error (at=1587) (waited=0ms): Address already in use: Cannot bind
Error (at=1740) (waited=0ms): Address already in use: Cannot bind
end...
I did get some errors but the socket get closed properly... which is oki for my needs
TEST WITH CHANNEL
public void testConnectCloseWithChannel() {
long tCumulative = 0;
int errAt = -1;
System.out.println("start...");
for (int i = 0; i < 4000; i++) {
try {
errAt = i;
Selector selector = Selector.open();
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(true);
channel.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 9005));
SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
clientKey.cancel();
channel.close();
//success at last
tCumulative = 0;
} catch (Exception e) {
System.out.println("Error (at="+errAt+") (waited="+tCumulative+"ms): " + e.getMessage());
tCumulative+=50;
try {
Thread.sleep(tCumulative);
} catch (InterruptedException e1) {
}
i--;
}
}
System.out.println("end...");
}
NOTE: It the channel.register is commented the test works ..
RESULT WITH CHANNEL
start...
Error (at=0) (waited=0ms): null
Error (at=0) (waited=50ms): Address already in use: bind
Error (at=0) (waited=100ms): Address already in use: bind
Error (at=0) (waited=150ms): Address already in use: bind
...
Thanks for any help
I did get some errors but the socket get closed properly... which is
oki for my needs
No, in case you've got errors your channel is NOT closed properly.
You have to do close in the finally clause of your try block.
Selector selector = Selector.open();
try
{
DatagramChannel channel = DatagramChannel.open();
try
{
channel.configureBlocking(true);
channel.socket().bind(
new InetSocketAddress(InetAddress.getLocalHost(), 9005)
);
SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
clientKey.cancel();
}
finally
{
channel.close();
}
}
finally
{
selector.close( )
}
Some parts of a channel close are deferred to the next select() if the channel is registered with a Selector. It is documented somewhere in the forest of Selector, AbstractSelector, SelectorSpi, SelectableChannel, AbstractSelectableChannel, where I can never find it when I need it. If you're within the select loop and thread when you close the channel, you can make it immediate by calling selectNow().

Why does InetAddress.isReachable return false, when I can ping the IP address?

InetAddress byName = InetAddress.getByName("173.39.161.140");
System.out.println(byName);
System.out.println(byName.isReachable(1000));
Why does isReachable return false? I can ping the IP.
The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.
The issue
There is alot of chatter about this :
Here are other, similar questions :
Detect internet Connection using Java
How do I test the availability of the internet in Java?
And even a reported bug on this same matter :
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4921816
Part 1 : A reproducible example of the problem
Note that in this case, it fails.
//also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd"
InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
for (InetAddress address : addresses) {
if (address.isReachable(10000))
{
System.out.println("Connected "+ address);
}
else
{
System.out.println("Failed "+address);
}
}
//output:*Failed www.google.com/74.125.227.114*
Part 2 : A Hackish Workaround
As an alternative, you can do this :
// in case of Linux change the 'n' to 'c'
Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).
This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.
Much simpler - but of course it is platform specific.
And there may be certain privilege caveats to using this command - but I find it works on my machines.
PLEASE Note that :
1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable).
2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.
I came here to get an answer for this same question, but I was unsatisfied by any of the answers because I was looking for a platform independent solution. Here is the code which I wrote and is platform independent, but requires information about any open port on the other machine (which we have most of the time).
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try {
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
}
return true;
} catch (IOException ex) {
return false;
}
}
Update: Based on a recent comment to this answer, here is a succinct version of the above code:
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
return true;
} catch (IOException ex) {
return false;
}
}
If you only want to check if it is connected to internet use this method , It returns true if internet is connected, Its preferable if you use the address of the site you are trying to connect through the program.
public static boolean isInternetReachable()
{
try {
//make a URL to a known source
URL url = new URL("http://www.google.com");
//open a connection to that source
HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();
//trying to retrieve data from the source. If there
//is no connection, this line will fail
Object objData = urlConnect.getContent();
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Just mentioning it explicitly since the other answers don't. The ping part of isReachable() requires root access on Unix. And as pointed out by bestsss in 4779367:
And if you ask why ping from bash doesn't, actually it does need as well. Do that ls -l /bin/ping.
Since using root was not an option in my case the solution was to allow access to port 7 in the firewall to the specific server I was interested in.
I am not sure what was the state when the original question was asked back in 2012.
As it stands now, ping will be executed as a root. Through the ping executable's authorization you will see the +s flag, and the process belonging to root, meaning it will run as root. run ls -liat on where the ping is located and you should see it.
So, if you run InetAddress.getByName("www.google.com").isReacheable(5000) as root, it should return true.
you need proper authorizations for the raw socket, which is used by ICMP (the protocol used by ping)
InetAddress.getByName is as reliable as ping, but you need proper permissions on the process to have it running properly.
Since you can ping the computer, your Java process should run with sufficient privileges to perform the check. Probably due to use of ports in the lower range. If you run your java program with sudo/superuser, I'll bet it works.
I would suggest that the ONLY reliable way to test an internet connection is to actually connect AND download a file, OR to parse the output of an OS ping call via exec(). You cannot rely on the exit code for ping and isReachable() is crap.
You cannot rely on a ping exit code as it returns 0 if the ping command executes correctly. Unfortunately, ping executes correctly if it can't reach the target host but gets a "Destination host unreachable" from your home ADSL router. This is kind of a reply that gets treated as a successfull hit, thus exit code = 0. Have to add though that this is on a Windows system. Not checked *nixes.
private boolean isReachable(int nping, int wping, String ipping) throws Exception {
int nReceived = 0;
int nLost = 0;
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("ping -n " + nping + " -w " + wping + " " + ipping);
Scanner scanner = new Scanner(process.getInputStream());
process.waitFor();
ArrayList<String> strings = new ArrayList<>();
String data = "";
//
while (scanner.hasNextLine()) {
String string = scanner.nextLine();
data = data + string + "\n";
strings.add(string);
}
if (data.contains("IP address must be specified.")
|| (data.contains("Ping request could not find host " + ipping + ".")
|| data.contains("Please check the name and try again."))) {
throw new Exception(data);
} else if (nping > strings.size()) {
throw new Exception(data);
}
int index = 2;
for (int i = index; i < nping + index; i++) {
String string = strings.get(i);
if (string.contains("Destination host unreachable.")) {
nLost++;
} else if (string.contains("Request timed out.")) {
nLost++;
} else if (string.contains("bytes") && string.contains("time") && string.contains("TTL")) {
nReceived++;
} else {
}
}
return nReceived > 0;
}
nping is number of try to ping ip(packets), if you have busy network or systems choose biger nping numbers.
wping is time waiting for pong from ip, you can set it 2000ms
for using this method u can write this:
isReachable(5, 2000, "192.168.7.93");
Or using this way:
public static boolean exists(final String host)
{
try
{
InetAddress.getByName(host);
return true;
}
catch (final UnknownHostException exception)
{
exception.printStackTrace();
// Handler
}
return false;
}
InetAddress.isReachable is flappy, and sometimes returns unreachable for addresses which we can ping.
I tried the following:
ping -c 1 <fqdn> and check the exit status.
Works for all the cases i had tried where InetAddress.isReachable doesn't work.
To Check Internet
public boolean isInternetAvailable() {
try {
InetAddress ipAddr = InetAddress.getByName("google.com");
//You can replace it with your name
return !ipAddr.equals("");
} catch (Exception e1) {
try {
Process p1 = java.lang.Runtime.getRuntime().exec("/system/bin/ping -W 1 -c 1 www.google.com");
int returnVal = 0;
returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
return reachable;
} catch (Exception e2) {
e2.printStackTrace();
return false;
}
}
}
To check network connectivity
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
}
Because isReachable is using the TCP protocol(by WireShark) The Ping command is using ICMP protocol,if you want to return true you need to open the 7 port

How to get the LAN IP of a client using Java?

How can i get the LAN IP-address of a computer using Java? I want the IP-address which is connected to the router and the rest of the network.
I've tried something like this:
Socket s = new Socket("www.google.com", 80);
String ip = s.getLocalAddress().getHostAddress();
s.close();
This seem to work on some cases, but sometimes it returns the loopback-address or something completely different. Also, it requires internet connection.
Does anyone got a more accurate method of doing this?
EDIT: Thought it would be better to ask here than in a comment..
What if you got many interfaces? For example, one for cable, one for wifi and one for virtual box or so. Is it impossible to actually see which one is connected to the network?
Try java.net.NetworkInterface
import java.net.NetworkInterface;
...
for (
final Enumeration< NetworkInterface > interfaces =
NetworkInterface.getNetworkInterfaces( );
interfaces.hasMoreElements( );
)
{
final NetworkInterface cur = interfaces.nextElement( );
if ( cur.isLoopback( ) )
{
continue;
}
System.out.println( "interface " + cur.getName( ) );
for ( final InterfaceAddress addr : cur.getInterfaceAddresses( ) )
{
final InetAddress inet_addr = addr.getAddress( );
if ( !( inet_addr instanceof Inet4Address ) )
{
continue;
}
System.out.println(
" address: " + inet_addr.getHostAddress( ) +
"/" + addr.getNetworkPrefixLength( )
);
System.out.println(
" broadcast address: " +
addr.getBroadcast( ).getHostAddress( )
);
}
}
At first: There is no single address. Your machine has at least two adresses (127.0.0.1 on "lo" and maybe 192.168.1.1 on "eth1").
You want this: Listing network interfaces
As you may expect, you cannot automatically detect which one is connected to any of your routers, since this needs potentially complex parsing of your routing tables. But if you just want any non-local address this should be enought. To be sure, try to use this at least one time on vista or Windows 7, since they add IPv6 addresses.
import java.io.*;
import java.net.*;
import java.util.*;
import static java.lang.System.out;
public class ListNets
{
public static void main(String args[]) throws SocketException {
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(nets))
displayInterfaceInformation(netint);
}
static void displayInterfaceInformation(NetworkInterface netint) throws SocketException {
out.printf("Display name: %s\n", netint.getDisplayName());
out.printf("Name: %s\n", netint.getName());
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
out.printf("InetAddress: %s\n", inetAddress);
}
out.printf("\n");
}
}
The following is sample output from the example program:
Display name: bge0
Name: bge0
InetAddress: /fe80:0:0:0:203:baff:fef2:e99d%2
InetAddress: /121.153.225.59
Display name: lo0
Name: lo0
InetAddress: /0:0:0:0:0:0:0:1%1
InetAddress: /127.0.0.1
This is a method I've used for a while. It includes a little hack to figure out the externally visible ip-address as well.
private List<String> getLocalHostAddresses() {
List<String> addresses = new ArrayList<String>();
try {
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
while (e.hasMoreElements()) {
NetworkInterface ni = e.nextElement();
Enumeration<InetAddress> e2 = ni.getInetAddresses();
while (e2.hasMoreElements())
addresses.add(e2.nextElement().getHostAddress());
}
URL u = new URL("http://whatismyip.org");
BufferedReader in = new BufferedReader(new InputStreamReader(
u.openStream()));
addresses.add(in.readLine());
in.close();
} catch (Exception ignore) {
}
return addresses;
}
try {
InetAddress addr = InetAddress.getLocalHost();
// Get IP Address
byte[] ipAddr = addr.getAddress();
// Get hostname
String hostname = addr.getHostName();
} catch (UnknownHostException e) {
}
As Daniel already pointed out, you cannot know which interface is the one "connected". What if, for example, the computer has multiple network interface cards which are both connected to separate physical LANs?
Let the user decide which interface to use or try them all, depending on what your use case is.

Categories