1. 简介

在网络编程中,获取同一子网内已连接设备的IP地址列表对网络监控和设备管理至关重要。这有助于识别特定IP范围内的活跃设备并确保其可达性。

本文将探讨用Java扫描子网IP地址的多种方法:

  • 使用Java原生InetAddress
  • 结合Java 8 Stream API优化代码
  • 使用Apache Commons Net库实现高级子网处理

2. IP地址与子网基础

IP地址唯一标识网络中的设备,而子网则将IP地址分组管理。子网通过IP地址和子网掩码(如192.168.1.0/24)表示,其中子网掩码划分网络部分和主机部分。

以子网192.168.1.0/24为例:

  • 覆盖范围:192.168.1.1192.168.1.254
  • 网络部分:前三个字节(192.168.1
  • 主机部分:最后一个字节(1-254)

⚠️ 子网掩码255.255.255.0表示前三个字节为网络部分,最后一个字节为主机标识符。

动态获取子网的Java实现:

private String getSubnet() throws UnknownHostException {
    InetAddress localHost = InetAddress.getLocalHost();
    byte[] ipAddr = localHost.getAddress();
    return String.format("%d.%d.%d", (ipAddr[0] & 0xFF), (ipAddr[1] & 0xFF), (ipAddr[2] & 0xFF));
}

此方法动态提取本机IP的前三字节作为子网,适应不同网络环境。

3. 使用Java的InetAddress类

InetAddress类是检测设备可达性的基础工具。通过动态获取子网后,可扫描1-254范围内的所有IP:

@Test
public void givenSubnet_whenScanningForDevices_thenReturnConnectedIPs() throws Exception {
    String subnet = getSubnet();
    List<String> connectedIPs = new ArrayList<>();

    for (int i = 1; i <= 254; i++) {
        String ip = subnet + "." + i;
        if (InetAddress.getByName(ip).isReachable(100)) {
            connectedIPs.add(ip);
        }
    }

    assertFalse(connectedIPs.isEmpty());
}

核心逻辑:

  1. 组装完整IP地址(如192.168.1.1
  2. 使用isReachable(100)检测100ms内可达性
  3. 收集可达IP到列表

✅ 实际结果取决于当前网络连接的设备数量

3.1. 用Java 8 Stream API优化扫描

Java 8的Stream API能以函数式风格简化代码:

@Test
public void givenSubnet_whenUsingStream_thenReturnConnectedIPs() throws UnknownHostException {
    String subnet = getSubnet();

    List<String> connectedIPs = IntStream.rangeClosed(1, 254)
            .mapToObj(i -> subnet + "." + i)
            .filter(ip -> {
                try {
                    return InetAddress.getByName(ip).isReachable(100);
                } catch (Exception e) {
                    return false;
                }
            })
            .toList();

    assertFalse(connectedIPs.isEmpty());
}

优化点:

  • IntStream.rangeClosed(1, 254)生成IP主机段
  • mapToObj组装完整IP地址
  • filter过滤可达设备
  • 异常处理简化为返回false

虽然功能不变,但代码更简洁,充分利用了Stream API的特性。

4. 使用Apache Commons Net库处理高级子网操作

对于复杂子网管理,推荐使用Apache Commons Net库。以下示例展示如何检测子网中开放80端口的设备:

@Test
public void givenSubnet_whenCheckingForOpenPorts_thenReturnDevicesWithOpenPort() throws UnknownHostException {
    SubnetUtils utils = new SubnetUtils(getSubnet() + ".0/24");
    int port = 80;
    List<String> devicesWithOpenPort = Arrays.stream(utils.getInfo().getAllAddresses())
            .filter(ip -> {
                TelnetClient telnetClient = new TelnetClient();
                try {
                    telnetClient.setConnectTimeout(100);
                    telnetClient.connect(ip, port);
                    return telnetClient.isConnected();
                } catch (Exception e) {
                    return false;
                } finally {
                    try {
                        if (telnetClient.isConnected()) {
                            telnetClient.disconnect();
                        }
                    } catch (IOException ex) {
                        System.err.println(ex.getMessage());
                    }
                }
            })
            .toList();

    assertFalse(devicesWithOpenPort.isEmpty());
}

关键步骤:

  1. SubnetUtils生成子网所有有效IP(如192.168.1.0/24
  2. 使用TelnetClient尝试连接指定端口
  3. 连接成功则记录IP
  4. finally块确保资源释放

⚠️ 实际扫描时注意:

  • 防火墙可能阻止连接
  • 超时设置需根据网络环境调整
  • 大规模扫描可能触发网络设备安全机制

5. 总结

本文系统介绍了Java获取子网IP列表的三种方案: | 方法 | 适用场景 | 优势 | 劣势 | |------|----------|------|------| | InetAddress | 简单可达性检测 | 无需依赖库 | 功能基础 | | Stream API | 代码优化 | 简洁易读 | 性能提升有限 | | Apache Commons Net | 高级子网操作 | 支持端口扫描等 | 需引入外部库 |

完整代码示例可在GitHub获取。根据实际需求选择合适方案,避免在生产环境进行高频扫描。


原始标题:Get a List of IP Connected in Same Network (Subnet) using Java | Baeldung