如何使用Java获取连接在同一网络(子网)中的IP列表

44

如何使用Java获取连接到同一子网的设备的IP地址列表?


3
“IPs connected in LAN” 您具体指的是什么? - Pekka
你提供的所有帖子都需要花费一些时间,需要8分钟才能搜索到连接到局域网的50台计算机,我想要最快的方法来获取连接到局域网的IP地址,以便我可以在JCOMBOBOX上显示它。请问有人能给我最快的方法吗? - Nilesh410451
8个回答

54

如果您的网络主机对 ICMP 包(ping)做出响应(JDK 5 及以上版本),则此方法应该有效:

public void checkHosts(String subnet){
   int timeout=1000;
   for (int i=1;i<255;i++){
       String host=subnet + "." + i;
       if (InetAddress.getByName(host).isReachable(timeout)){
           System.out.println(host + " is reachable");
       }
   }
}

可以像这样为子网(192.168.0.1-254)调用方法:

checkHosts("192.168.0");

没有测试过,但应该像这样工作。显然,这只检查 IP 地址的最后一个字节中的 254 个主机...

检查:

http://download-llnw.oracle.com/javase/6/docs/api/java/net/InetAddress.html#isReachable%28int%29 http://blog.taragana.com/index.php/archive/how-to-do-icmp-ping-in-java-jdk-15-and-above/

希望能有所帮助。


5
提供了一个好的解决方案,“LAN”可以理解为“D类IP子网”。 - user207421
感谢您提供的解释。 - jmj
操作系统肯定已经有这些信息了,有没有什么方法可以检索它,因为这个实现可能需要一段时间... - Troyseph
我正在寻找的是一个伟大而优雅的解决方案。 - Sam Orozco
我在想这可能会很慢,有没有更快的方法? - Sumukha Pk
显示剩余3条评论

6

要列出连接在局域网中的主机,您需要对子网上所有可用的IP地址进行ping。但是,ping消息可能会受到防火墙的限制,因此更安全的方法是打开到局域网IP地址范围内每个IP地址的套接字。


2
socket?连接到哪个端口?如何确保防火墙不会阻止它? - Gopi
2
提供基本信息以ping子网中的所有IP地址。 - YoK
4
局域网可以分割成多个子网。 - Steve Kuo
但是这样ping并获取所有本地wifi地址太慢了。 - Innocent

3
自Java 1.5以来,java.net.InetAddress中就有一种类似ping的方法:public boolean isReachable(int timeout)。您可以使用它来遍历子网中的所有IP地址...java-doc

1
我看到了另一个答案,它很好。但与实际情况相比速度较慢,不应在这种情况下使用。
以下是我的观点。
当我使用答案 https://dev59.com/8nA75IYBdhLWcg3wVniI#3345981 时, 代码:
import java.net.InetAddress;
public class Main {
    public static void main(String[] args)  throws Exception{
        long initialT = System.currentTimeMillis();
        checkHosts("192.168.0");
        long finalT = System.currentTimeMillis();
        System.out.println("Scan Completed taking " + (finalT - initialT) + " miliseconds approximately!");
    }
    
    public static void checkHosts(String subnet) throws Exception{
   int timeout=1000;
   for (int i=1;i<255;i++){
       String host=subnet + "." + i;
       if (InetAddress.getByName(host).isReachable(timeout)){
           System.out.println(host + " is reachable");
       }
   }
}
}

输出:

sudo java Main
[sudo] password for jaysmito: 
192.168.0.1 is reachable
192.168.0.2 is reachable
192.168.0.3 is reachable
192.168.0.4 is reachable
192.168.0.10 is reachable
Scan Completed taking 250151 miliseconds approximately!

这段代码运行缓慢,但我尝试使用这个概念来制作更好的版本: 代码:
import java.net.*;
import java.io.*;
import java.util.*;

class AddressFinderLevel4 extends Thread{
  private String addmask;
  private Stack<String> stack;
  private int start, end;

  public AddressFinderLevel4(String addmask, Stack stack, int start, int end){
    this.addmask = addmask;
    this.stack = stack;
    this.start = start;
    this.end = end;
  }

  @Override
  public void run(){
    try{
        int timeout=1000;
      for(int i = start; i <= end; i++){
        String host=addmask + "." + i;
            if (InetAddress.getByName(host).isReachable(timeout)){
                stack.push(host);
            }
      }
    }catch(Exception ex){

    }
  }
}

class AddressFinderLevel3 extends Thread{
  private String addmask;
  private Stack<String> stack;
  private int start, end;
  private int packSize;

  public AddressFinderLevel3(String addmask, Stack stack, int packSize, int start, int end){
    this.addmask = addmask;
    this.stack = stack;
    this.start = start;
    this.end = end;
    this.packSize = packSize;
  }

  @Override
  public void run(){
    try{
      for(int i = start; i <= end; i++){
        int j = 1;
        String host =  addmask + "." + i;
        while(j<=255){
          AddressFinderLevel4 addressFinderLevel4 = new AddressFinderLevel4(host, stack, j, j+packSize+5);
          addressFinderLevel4.start();
          j = j + packSize;
        }
      }
    }catch(Exception ex){
      ex.printStackTrace();
    }
  }
}



public class Main {
    public static void main(String[] args) throws Exception {
      System.out.println("Starting search!");
      Stack data = find();
      Thread.sleep(1000);
      System.out.println("Data found in 1000 miliseconds");
      data.forEach(System.out::println);
      Thread.sleep(10000);
      System.out.println("Data found in 10000 miliseconds");
      data.forEach(System.out::println);
      Thread.sleep(25000);
      System.out.println("Data found in 25000 miliseconds");
      data.forEach(System.out::println);
    }

    public static Stack find(){
      Stack<String> stack = new Stack<String>();
      AddressFinderLevel3 finder = new AddressFinderLevel3("192.168", stack, 10, 0, 255);
      finder.start();
      return stack;
    }
}

输出结果:
sudo java Main
Starting search!
Data found in 1000 miliseconds
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
Data found in 10000 miliseconds
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.99.152
192.168.0.10
192.168.102.227
192.168.99.161
Data found in 25000 miliseconds
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.99.152
192.168.0.10
192.168.102.227
192.168.99.161

正如您所看到的,这个程序在更短的时间内扫描了更多的IP地址。

我也尝试对所有可能的IP地址进行扫描,但那需要太多的内存,也是不必要的!

这是一个更快的解决方案,因此应该表现更好!


如果我想获取主机名和MAC地址怎么办? - Shashi Patel

1

如果您想要一个连接到网络的所有主机列表,我认为唯一保证可行的方法是遍历IP地址列表并对它们进行ping测试。

话虽如此,如果您正在寻找更具体的内容,可能有一些可以查找的内容(例如RMI的注册表(LocateRegistry.getRegistry(host, port).list()))。

此外,如果您只想要给定主机拥有的所有IP地址,请查看NetworkInterface.getNetworkInterfaces()


1
不是的。LocateRegistry.getRegistry根本不进行任何通信。它只是构造一个Registry存根。 - user207421
1
调用list()应该可以。不管怎样,这有点无关紧要 - 我忘记了默认情况下RMI只允许对象在本地注册表中注册,因此您仍然需要在每个主机上检查注册表。您需要使用类似Bonjour的东西来进行服务发现 - 这就是我的观点。 - Scott

0

显示局域网上的活动地址

public static void main(String[] args) {
    try {
        Enumeration nis = NetworkInterface.getNetworkInterfaces();
        while(nis.hasMoreElements())
        {
            NetworkInterface ni = (NetworkInterface) nis.nextElement();
            Enumeration ias = ni.getInetAddresses();
            while (ias.hasMoreElements())
            {
                InetAddress ia = (InetAddress) ias.nextElement();
                System.out.println(ia.getHostAddress());
            }

        }
    } catch (SocketException ex) {
        Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
    }
}

输出

127.0.0.1
0:0:0:0:0:0:0:1
172.128.1.102

5
这个方法无法回答所提出的问题 - 它只会返回绑定到网络设备上的地址,也就是本地主机在各个网络上拥有的地址。 - Daniel Underwood
是的,我同意@danielunderwood的观点。 - Sumukha Pk

-1

对我来说,这些都没有起作用,因为我已经创建了服务器,它没有响应这些ping。因此,我创建了一种机制,使服务器回复ping,并对子网中的所有地址使用暴力检查方法。

附注:写这篇文章是因为有人创建自己的服务器可能需要这个。


-3
这里的一个问题是,“LAN”和“connected”这两个术语在TCP/IP中都没有意义。如果您的局域网恰好对应于D类子网,则在类D子网中调用isReachable()来检查所有主机可能有效。
您最好查看SAMBA,它可以通过SMBs查询LAN成员,因此您将使用与您相同含义的技术。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接