使用 Java 取得同一網路(子網路)中連接的 IP 列表
一、簡介
在網路中,檢索相同網路(子網路)內連接的 IP 位址清單對於網路監控和裝置管理等任務至關重要。此外,這有助於識別特定 IP 範圍內的活動設備並確保它們可存取。
在本教程中,我們將探索 Java 中掃描和檢索相同子網路內的 IP 位址清單的各種方法。我們將介紹使用 Java 的InetAddress類別的解決方案以及使用 Java 8 Stream API 的增強功能。最後,我們將使用 Apache Commons Net 庫來示範更進階的子網路處理。
2.了解IP位址和子網
IP 位址唯一標識網路上的設備,而子網路將一系列 IP 位址組合在一起。子網路允許將網路劃分為更小、更易於管理的區塊,有助於提高效能和安全性。
子網路通常由 IP 位址和子網路遮罩表示(例如192.168.1.0/24 )。子網遮罩定義了 IP 位址的哪一部分代表網絡,哪一部分標識各個主機。
例如,子網路192.168.1.0/24涵蓋從192.168.1.1到192.168.1.254的所有位址。在本例中,前三個八位元組 ( 192.168.1 ) 代表網絡,最後一個八位元組可以是 1 到 254 之間的任意數字,用於標識各個主機。
子網遮罩255.255.255.0表示 IP 位址的前三部分代表網絡,而最後一部分則因主機而異。
讓我們看看如何在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類
檢查網路中裝置的可及性的最簡單方法之一是使用 Java 的InetAddress類別。此外,此類允許我們驗證特定 IP 位址的裝置在給定的逾時時間內是否可達。
一旦我們動態確定了子網,我們就可以透過將 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,我們使用InetAddress.getByName()方法建立一個InetAddress物件。然後,我們使用isReachable()方法檢查它是否可達。如果設備可訪問,我們會將 IP 位址新增至清單。
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()將產生的數字附加到動態檢索的子網路中,並filter()來檢查每個IP是否可達。
雖然這沒有引入新的網路功能,但它演示瞭如何使用 Stream API(Java 8 中引入的強大附加功能)來組織和簡化解決方案。
4. 使用 Apache Commons Net Library 進行高階子網路處理
對於更高階的子網路管理,我們可以使用Apache Commons Net函式庫,它提供了一個輕鬆處理子網路的實用程式。此函式庫的一個用例涉及使用TelnetClient (Apache Commons Net 庫提供的SocketClient的子類別)檢查子網路內設備上的開放連接埠(例如連接埠 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 )。對於每個 IP 位址,我們嘗試使用TelnetClient.connect()方法連接到連接埠 80。連線成功後,系統會將 IP 位址新增至開放連接埠的裝置清單。然後,它使用telnetClient.disconnect()在finally區塊中關閉連接,以確保正確的資源管理。
5. 結論
在本教程中,我們探索了使用 Java 掃描和檢索相同子網路內連接的 IP 位址清單的不同方法。
為了簡單起見,我們使用InetAddress類,使用 Java 8 的 Stream API 進行簡潔的函數式編程,並使用 Apache Commons Net 庫來實現更強大的子網路處理和連接埠掃描等高級任務。
與往常一樣,本文的完整程式碼範例可以 在 GitHub 上找到。