我的Windows系统有多个以太网适配器。鉴于以太网适配器的名称,我需要找到它的IP地址。
例如,我系统的ipconfig
命令输出为:
Ethernet adapter GB1:
Connection-specific DNS Suffix . :
IP Address. . . . . . . . . . . . : 0.0.0.0
Subnet Mask . . . . . . . . . . . : 0.0.0.0
Default Gateway . . . . . . . . . :
Ethernet adapter SWITCH:
Connection-specific DNS Suffix . :
IP Address. . . . . . . . . . . . : 10.200.1.11
Subnet Mask . . . . . . . . . . . : 255.255.255.0
IP Address. . . . . . . . . . . . : 10.200.1.51
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . :
Ethernet adapter LAN:
Connection-specific DNS Suffix . :
IP Address. . . . . . . . . . . . : 10.1.2.62
Subnet Mask . . . . . . . . . . . : 255.255.254.0
IP Address. . . . . . . . . . . . : 10.1.2.151
Subnet Mask . . . . . . . . . . . : 255.255.254.0
Default Gateway . . . . . . . . . : 10.1.2.1
注意:我不必担心无线适配器或任何其他类型的适配器。我只需要为以太网适配器执行此操作。
对于这个系统,我需要编写一个行为如下所示的Java类:
C:>java NameToIp GB1
0.0.0.0
C:>java NameToIp SWITCH
10.200.1.11
10.200.1.51
C:>java NameToIp LAN
10.1.2.62
10.1.2.151
使用java.net.NetworkInterface没有帮助。它的getName()和getDisplayName()方法不会打印出现在ipconfig
输出或Windows网络连接中的适配器连接名称。它们会打印实际的设备名称。例如,请考虑以下代码:
import java.util.Enumeration;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
public class ListInterfaces
{
public static void main(String[] args) throws SocketException, UnknownHostException {
Enumeration<NetworkInterface> nwInterfaces = NetworkInterface.getNetworkInterfaces();
while (nwInterfaces.hasMoreElements()) {
NetworkInterface nwInterface = nwInterfaces.nextElement();
System.out.print(nwInterface.getName() + ": " +
nwInterface.getDisplayName());
Enumeration<InetAddress> addresses = nwInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
System.out.print(" - " + address.getHostAddress());
}
System.out.println();
}
}
}
这将打印以下输出:
C:>java ListInterfaces
lo: MS TCP Loopback interface - 127.0.0.1
eth0: Broadcom BCM5709C NetXtreme II GigE (NDIS VBD Client) #
eth1: Broadcom BCM5709C NetXtreme II GigE (NDIS VBD Client) #2 - 10.200.1.11 - 10.200.1.51
eth2: Broadcom BCM5709C NetXtreme II GigE (NDIS VBD Client) #3 - 10.1.2.62 - 10.1.2.151
我编写了一个丑陋的黑客,它从ipconfig
的输出中提取指定适配器名称的IP地址。这是代码。
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.io.IOException;
public class NameToIp
{
public static ArrayList<String> getIP(String adapterName)
throws IOException, InterruptedException
{
// Run the Windows 'ipconfig' command and get its stdout
ProcessBuilder cmdBuilder = new ProcessBuilder("ipconfig");
Process process = cmdBuilder.start();
BufferedReader stdout = new BufferedReader(
new InputStreamReader(process.getInputStream()));
// Find the section for the specified adapter
String line;
boolean foundAdapter = false;
while ((line = stdout.readLine()) != null) {
line = line.trim();
if (line.equals("Ethernet adapter " + adapterName + ':')) {
foundAdapter = true;
break;
}
}
if (!foundAdapter) {
process.waitFor();
throw new IOException("Adapter not found");
}
// Find IP addresses in the found section
ArrayList<String> ips = new ArrayList<String>();
while ((line = stdout.readLine()) != null) {
// Stop parsing if we reach the beginning of the next
// adapter section in the output of ifconfig
if (line.length() > 0 && line.charAt(0) != ' ') {
break;
}
line = line.trim();
// Extract IP addresses
if (line.startsWith("IP Address.") ||
line.startsWith("IPv4 Address.")) {
int colonIndex;
if ((colonIndex = line.indexOf(':')) != 1) {
ips.add(line.substring(colonIndex + 2));
}
}
}
process.waitFor();
return ips;
}
public static void main(String[] args)
throws IOException, InterruptedException
{
// Print help message if adapter name has not been specified
if (args.length != 1) {
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
String prog = stack[stack.length - 1].getClassName();
System.err.println("Usage: java " + prog + " ADAPTERNAME");
System.err.println("Examples:");
System.err.println(" java " + prog +" \"Local Area Connection\"");
System.err.println(" java " + prog +" LAN");
System.err.println(" java " + prog +" SWITCH");
System.exit(1);
}
ArrayList<String> ips = getIP(args[0]);
for (String ip: ips) {
System.out.println(ip);
}
}
}
有没有更好的方法来解决这个问题?
答案 0 :(得分:3)
创建一个使用Windows API查询本地以太网地址并使用JNI调用dll的dll。
答案 1 :(得分:0)
我会回答我自己的问题。在SpaceTrucker's suggestion之后,我使用JNI创建了一个Java类,如下所示。
// NwInterface.java
import java.util.ArrayList;
public class NwInterface {
public native ArrayList<String> getAddresses(String adapterName);
static
{
System.loadLibrary("nwinterface");
}
}
然后我用C ++创建了'nwinterface'库,如下所示。
// nwinterface.cc
#include <iostream>
#include <winsock2.h>
#include <iphlpapi.h>
#include "NwInterface.h"
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "advapi32.lib")
bool GetFriendlyName(const char* adapterName, unsigned char* buffer,
unsigned long size)
{
HKEY hKey;
char key[1024];
_snprintf_s(key, sizeof key, _TRUNCATE,
"SYSTEM\\CurrentControlSet\\Control\\Network\\"
"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection",
adapterName);
long ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey);
if (ret != ERROR_SUCCESS) {
return false;
}
ret = RegQueryValueEx(hKey, "Name", 0, 0, buffer, &size);
if (ret != ERROR_SUCCESS) {
return false;
}
buffer[size - 1] = '\0';
return true;
}
JNIEXPORT jobject JNICALL Java_NwInterface_getAddresses(JNIEnv *env, jobject obj,
jstring jAdapterName)
{
// Create a Java ArrayList object
jclass arrayClass = env->FindClass("java/util/ArrayList");
jmethodID initMethod = env->GetMethodID(arrayClass, "<init>", "()V");
jmethodID addMethod = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
jobject ips = env->NewObject(arrayClass, initMethod);
// Get information about all adapters
IP_ADAPTER_INFO adapterInfo[128];
unsigned long bufferSize = sizeof adapterInfo;
unsigned long ret = GetAdaptersInfo(adapterInfo, &bufferSize);
// If there is an error, return empty ArrayList object
if (ret != NO_ERROR) {
return ips;
}
// Iterate through the information of each adapter and select the
// specified adapter
for (PIP_ADAPTER_INFO adapter = adapterInfo; adapter != NULL;
adapter = adapter->Next) {
char friendlyName[1024];
ret = GetFriendlyName(adapter->AdapterName,
(unsigned char *) friendlyName,
sizeof friendlyName);
if (ret == false) {
continue;
}
const char *adapterName = env->GetStringUTFChars(jAdapterName, 0);
if (strncmp(friendlyName, adapterName, sizeof friendlyName) == 0) {
for (PIP_ADDR_STRING addr = &(adapter->IpAddressList); addr != NULL;
addr = addr->Next) {
const char *ip = addr->IpAddress.String;
env->CallBooleanMethod(ips, addMethod, env->NewStringUTF(ip));
}
break;
}
}
return ips;
}
最后,我通过编写这个Java程序来测试Java类。
// NameToIp2.java
import java.util.ArrayList;
public class NameToIp2
{
public static void main(String[] args)
{
// Print help message if adapter name has not been specified
if (args.length != 1) {
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
String prog = stack[stack.length - 1].getClassName();
System.err.println("Usage: java " + prog + " ADAPTERNAME");
System.err.println("Examples:");
System.err.println(" java " + prog +" \"Local Area Connection\"");
System.err.println(" java " + prog +" LAN");
System.err.println(" java " + prog +" SWITCH");
System.exit(1);
}
// Use NwInterface class to translate
NwInterface nwInterface = new NwInterface();
ArrayList<String> ips = nwInterface.getAddresses(args[0]);
for (String ip: ips) {
System.out.println(ip);
}
}
}
编译和运行程序的步骤如下:
javac NameToIp2.java
javah -jni NwInterface
cl /LD /EHsc /I C:\jdk1.5.0_13\include /I C:\jdk1.5.0_13\include\win32 nwinterface.cc
这是输出:
C:>java NameToIp2 GB1
0.0.0.0
C:>java NameToIp2 SWITCH
10.200.1.11
10.200.1.51
C:>java NameToIp2 LAN
10.1.2.62
10.1.2.151