How to get the LAN IP of a client using Java? - 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.

Related

How to reduce time for finding ip address of all active pc in lan using java language

i am trying to get all ip address of active pcs in a network using java.
try {
InetAddress localhost = InetAddress.getLocalHost();
System.out.println(localhost.toString());
byte[] ip = localhost.getAddress();
for (int i = 1; i <= 254; i++)
{
ip[3] = (byte)i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(50))
{
System.out.println(address + " - Pinging... Pinging");
}
else if (!address.getHostAddress().equals(address.getHostName()))
{
System.out.println(address + " - DNS lookup known..");
}
}
}
catch(Exception e)
{
System.out.println(e);
}
This code is taking to much of time, so how to reduce this time
You are using public boolean isReachable(int timeout) throws IOException. Since you have 254 adress to check, in the worst case, this will take 12.7s (254 * 50ms).
You could reduce the timeout value or use more than one thread to do this.
Is it required to use JAVA ? You can create batchscript, which will be simpler. Netstat -a will give you list of all connected machines. You can use Process p = Runtime.getRuntime().exec('<your command>') in Java. Parse the output with ButteredReader class. Also make sure Netstat is installed on your machine.
Here's a possible modification of your code.
8 Pings are launched at the same time. It's possible to do so because you don't need the result of ping(n-1) before launching ping(n).
I think there's still a problem with your ping method, since it takes much more time than 50ms. I don't know enough about the corresponding methods.
import java.net.InetAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;
public class ParallelPing
{
public static void main(String[] args) throws InterruptedException, ExecutionException {
IntStream integers = IntStream.rangeClosed(0, 254);
ForkJoinPool forkJoinPool = new ForkJoinPool(8); // How many pings should be launched at the same time?
forkJoinPool.submit(() -> integers
.parallel()
.forEach(i -> ping(i))).get();
}
private static void ping(int i) {
System.out.println("Trying to ping " + i);
try {
InetAddress localhost = InetAddress.getLocalHost();
//System.out.println(localhost.toString());
byte[] ip = localhost.getAddress();
ip[3] = (byte) i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(50)) {
System.out.println(address + " - Pinging... Pinging");
} else if (!address.getHostAddress().equals(address.getHostName())) {
System.out.println(address + " - DNS lookup known..");
}
} catch (Exception e) {
System.out.println(e);
}
}
}

find ip address of all devices on network with particular port number open

Socket socket = new Socket();
try {
Process process = Runtime.getRuntime().exec("arp -i en0 -a -n");
process.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while (reader.ready()) {
String ip = reader.readLine();
ip = ip.substring(3, ip.indexOf(')'));
try {
socket.connect(new InetSocketAddress(ip, 1234), 1000);
System.out.println("Found socket!");
} catch (ConnectException | SocketTimeoutException ignored) {
}
}
if (socket == null) {
System.err.println("Could not find socket.");
}
} catch (Exception e) {
e.printStackTrace();
}
i found this code on stackoverflow bt it is for mac and i need to find an alternative for windows O.S .
on windows it gives an exception
Well, to begin with I don't believe there is a -i parameter for the ARP (Address Resolution Protocol) used in Windows. There is a -n parameter but it's -N whereas the N is in uppercase. Obviously the ARP command line is wrong and you should be checking this yourself using the Windows Command Prompt window. You can see all the available parameters for ARP by simply entering arp within the Command Prompt window.
To retrieve the ARP Table you just need to supply: "arp -a" but you'll receive more than you bargained for and it will be up to you to parse out the required IP address to your connected devices which I would think would be Dynamic IP's. Here is an example of a ARP Table from a Windows 10 box:
Interface: 192.168.0.25 --- 0x2
Internet Address Physical Address Type
192.168.0.69 25-ad-42-bb-bd-65 dynamic
192.168.0.254 b8-29-34-f9-27-65 dynamic
192.168.0.255 ff-ff-ff-ff-ff-ff static
224.0.0.2 01-00-5e-00-00-02 static
224.0.0.22 01-00-5e-00-00-16 static
224.0.0.251 01-00-5e-00-00-fb static
224.0.0.252 01-00-5e-00-00-fc static
224.0.0.253 01-00-5e-00-00-fd static
239.255.255.250 01-00-5e-7f-ff-fa static
239.255.255.253 01-00-5e-7f-ff-fd static
255.255.255.255 ff-ff-ff-ff-ff-ff static
As mentioned earlier, I believe what you want are the Dynamic IP Addresses but whatever it is you want it will be up to you to parse out and clean up the data. When you do parse out the desired data it would be a good idea to place it into a List Array. Below I provide a small runnable which should work on your Windows computer:
package networkdevices;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
public class NetworkDevices {
private static int port = 1234;
public static void main(String[] args) {
getNetworkDevices();
}
private static void getNetworkDevices(){
Socket socket = new Socket();
try {
Process process = Runtime.getRuntime().exec("arp -a");
process.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String ip = null;
List<String> ipList = new ArrayList<>(); // List<> Array to hold dynamic IP Addresses
while ((ip = reader.readLine()) != null) {
ip = ip.trim(); // Trim the data
if (!ip.equals("")) {
if (!ip.equals("")) {
// Remove all the unwanted spaces between data provided by
// the ARP Table when it is generated.
while (ip.contains(" ")) { ip = ip.trim().replace(" ", " "); }
// Split each data line into a String Array for processing
String[] dataArray = ip.split(" ");
// For console output display only...
if (dataArray[0].toLowerCase().startsWith("interface:")) {
System.out.println("Locating Devices Connected To: " + dataArray[1]);
}
// If the data line contains the word "dynamic"
// then add the IP address on that line to the
// List<> Array...
if (dataArray[2].equalsIgnoreCase("dynamic")) {
ipList.add(dataArray[0]);
// For console output display only...
System.out.println("Device Located On IP: " + dataArray[0]);
}
}
}
}
// Close the Reader
reader.close();
// try to connect to the device....
// You'll need to play with this.
try {
for (int i = 0; i < ipList.size(); i++) {
ip = ipList.get(i);
socket.connect(new InetSocketAddress(ip, port), 1000);
if (socket == null) {
System.err.println("Could not find socket.");
}
else {
System.out.println("Found socket for: " + ip);
}
socket.close();
}
} catch (ConnectException | SocketTimeoutException ex) {
System.out.println("\nSOCKET ERROR - " + ex.getMessage());
}
} catch (IOException | InterruptedException e) {
System.out.println("\nPROCESS/READER ERROR - " + e.getMessage());
}
}
}
This added answer is towards your second question regarding the Socket Connections. This should have been started as another topic altogether but never the less....
Unfortunately it's not as simple as flopping down a Socket object and expecting it to connect to your found devices. There are several things to consider for each device such as Firewall protection, Anti-Virus protection, Connection requirements of the device itself like the port number, etc., etc. You will also have more success making a connection with a common port like 80 than something obscure like 1234.
In my opinion, your Socket connection should be a little more robust so as to at least receive acknowledgment as to why your connection might fail or be successful. As a matter of fact (IMO), your Socket connections should be done from a different method altogether.
Again I provide you with yet another runnable example but this time I have made a few changes and added a couple more methods. The first change I made was I have renamed the getNetworkDevices() method to getNetworkDeviceIPs() and have it actually return a string List<> Array of the detected device IP's. The second change is that I removed the Socket connection code from the getNetworkDeviceIPs() method and placed Socket Connection code into a different method named connectToDevices().
As mentioned earlier, I have added a couple new methods to the new runnable example shown below. The first method is named getDeviceName() and this method is passed an IP Address from the List<> Array retrieved from the getNetworkDeviceIPs() method. Each IP contained within the elements of the List<> Array is iterated through and checked through this method so as to display the Host Name of that device (along with the IP Address) within the console.
The second new method (as we touched on earlier) is named connectToDevices() which is passed the List<> Array retrieved from the getNetworkDeviceIPs() method. This method will try to open a socket connection to each Device IP Address contained within the String List<> Array. This method currently returns nothing (it's void) but is does display connection results within the Console window as to whether or not it was successful. You can modify this method of course to return the results in whatever you like.
Here is the new example runnable demonstrating all the above mentioned items:
package networkdevices;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
public class NetworkDevices {
public static int port = 80;
public static void main(String[] args) {
//Get devices from system ARP Table and
// place their IP's into a List<> Array...
List<String> ipList = getNetworkDeviceIPs(port);
// Iterate trough the List<> Array and display
// Device names stored within with the getDeviceName()
// method...
System.out.println("\nListing Device Names - Please Wait...");
for (int i = 0; i < ipList.size(); i++) {
System.out.println(getDeviceName(ipList.get(i)));
}
// Try to connect to each Device that is storred
// within the List<> Array....
System.out.println("\nTrying To Connect To Devices...");
connectToDevices(ipList, port);
}
private static List<String> getNetworkDeviceIPs(int portNumber){
Socket socket = new Socket();
List<String> ipList = new ArrayList<>(); // List<> Array to hold IP Addresses
try {
Process process = Runtime.getRuntime().exec("arp -a");
process.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String ip = null;
while ((ip = reader.readLine()) != null) {
ip = ip.trim(); // Trim the data
if (!ip.equals("")) {
if (!ip.equals("")) {
// Remove all the unwanted spaces between data provided by
// the ARP Table when it is generated.
while (ip.contains(" ")) { ip = ip.trim().replace(" ", " "); }
// Split each data line into a String Array for processing
String[] dataArray = ip.split(" ");
// For console output display only...
if (dataArray[0].toLowerCase().startsWith("interface:")) {
System.out.println("Locating Devices Connected To: " + dataArray[1]);
}
// If the data line contains the word "dynamic"
// then add the IP address on that line to the
// List<> Array...
if (dataArray[2].equalsIgnoreCase("dynamic")) {
ipList.add(dataArray[0]);
// For console output display only...
System.out.println("Device Located On IP: " + dataArray[0]);
}
}
}
}
// Close the Reader
reader.close();
}
catch (IOException | InterruptedException e) {
System.out.println("\nPROCESS/READER ERROR - " + e.getMessage());
}
return ipList;
}
private static String getDeviceName(String localIP) {
String result = "";
try {
InetAddress address = InetAddress.getByName(localIP);
if (address.isReachable(500)) {
// Device is turned on and can be pinged!;
result = address.toString();
}
else if (!address.getHostAddress().equals(address.getHostName())) {
// Device is identified in a DNS lookup!
result = address.toString();
}
else {
// if you keep getting something like "Unknown Device!/192.168.0.5 then the host
// address and host name are the same, meaning the host name could not be resolved.
// This means that either your router just isn't storing the information OR those
// devices just choose not to submit their host name to the router, and that is why
// you will continually get this message. Apparently, there is no way around this
// because those device names literally aren't stored anywhere.
result = "Unknown Device!/" + address.toString().substring(0,address.toString().indexOf("/"));
}
}
catch (UnknownHostException ex) { System.out.println(ex.getMessage()); }
catch (IOException ex) { System.out.println(ex.getMessage()); }
return result;
}
private static void connectToDevices(List<String> localIPAddresses, int port) {
// try to connect to the device(s)....
// You'll need to play with this.
for (int i = 0; i < localIPAddresses.size(); i++) {
if (i > 0) { System.out.println(""); }
try {
System.out.println("Connecting to: " + localIPAddresses.get(i) + " on port: " +
port + " - Please Wait...");
Socket thisSystem = new Socket(localIPAddresses.get(i), port);
System.out.println("Just connected to: " + thisSystem.getRemoteSocketAddress());
OutputStream outToServer = thisSystem.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeUTF("Hello from: " + thisSystem.getLocalSocketAddress());
InputStream inFromServer = thisSystem.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
System.out.println("Device says " + in.readUTF());
thisSystem.close();
}
catch(IOException e) { System.out.println(e.getLocalizedMessage()); }
}
}
}

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.

Identify the kind of network interface

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;
}
}

Socket program for Server using System IP Address

I'm trying to run a server application in PC using ServerSocket, for that I trying to get the system's IP address to start the server and to wait for client to connect, for that I've written,
InetAddress inetAddress = InetAddress.getLocalHost();
ServerSocket serverSocket;
if (serverSocket == null)
serverSocket = new ServerSocket(1000, 0, inetAddress);
Socket socket=serverSocket.accept();
Its working correctly in the Window OS, when I try this application in Unix OS its not working for me, I tried to print the IP address using,
System.out.println(inetAddress.getHostAddress);
in Windows OS correct IP address gets printed but in Unix OS, what I got was
127.0.0.1
so the server is not working, I have not tried this in Mac OS, so is there any way to start the server using the system's default IP address in any OS.
Thanks.
This appears to be a pretty common issue. See the following links for some possible solutions:
java InetAddress.getLocalHost(); returns 127.0.0.1 ... how to get REAL IP?
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037
Specifically, the work around and evaluation in the sun bug link explains how the function works on linux and how to make sure your linux box is properly set up to return the correct ip when queried from java.
InetAddress localhost = InetAddress.getLocalHost();
// this code assumes IPv4 is used
byte[] ip = localhost.getAddress();
for (int i = 1; i <= 254; i++) {
ip[3] = (byte)i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(1000))
{
// machine is turned on and can be pinged
}
else if (!address.getHostAddress().equals(address.getHostName()))
{
// machine is known in a DNS lookup
}
else
{
// the host address and host name are equal, meaning the host name could not be resolved
}
}
Just pass null for the InetAddress. Also be aware that your specified backlog may be adjusted up or down by the system. If you don't have a really good reason for specifying it just use new ServerSocket(0).
Try this example :
import java.net.*;
import java.util.*;
import java.util.regex.Pattern;
public class GetPublicHostname
{
public static void main(String[] args) throws Throwable {
System.out.println("The IP : " + tellMyIP());
}
public static String tellMyIP()
{
NetworkInterface iface = null;
String ethr;
String myip = "";
String regex = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
try
{
for(Enumeration ifaces = NetworkInterface.getNetworkInterfaces();ifaces.hasMoreElements();)
{
iface = (NetworkInterface)ifaces.nextElement();
ethr = iface.getDisplayName();
if (Pattern.matches("eth[0-9]", ethr))
{
System.out.println("Interface:" + ethr);
InetAddress ia = null;
for(Enumeration ips = iface.getInetAddresses();ips.hasMoreElements();)
{
ia = (InetAddress)ips.nextElement();
if (Pattern.matches(regex, ia.getCanonicalHostName()))
{
myip = ia.getCanonicalHostName();
return myip;
}
}
}
}
}
catch (SocketException e){}
return myip;
} }

Categories