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.1
到192.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());
}
核心逻辑:
- 组装完整IP地址(如
192.168.1.1
) - 使用
isReachable(100)
检测100ms内可达性 - 收集可达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());
}
关键步骤:
SubnetUtils
生成子网所有有效IP(如192.168.1.0/24
)- 使用
TelnetClient
尝试连接指定端口 - 连接成功则记录IP
finally
块确保资源释放
⚠️ 实际扫描时注意:
- 防火墙可能阻止连接
- 超时设置需根据网络环境调整
- 大规模扫描可能触发网络设备安全机制
5. 总结
本文系统介绍了Java获取子网IP列表的三种方案: | 方法 | 适用场景 | 优势 | 劣势 | |------|----------|------|------| | InetAddress | 简单可达性检测 | 无需依赖库 | 功能基础 | | Stream API | 代码优化 | 简洁易读 | 性能提升有限 | | Apache Commons Net | 高级子网操作 | 支持端口扫描等 | 需引入外部库 |
完整代码示例可在GitHub获取。根据实际需求选择合适方案,避免在生产环境进行高频扫描。