简体   繁体   English

使用Java 1.5在Windows中获取以太网适配器的IPv4地址

[英]Get IPv4 addresses of an ethernet adapter in Windows using Java 1.5

Problem 问题

My Windows system has multiple ethernet adapters. 我的Windows系统有多个以太网适配器。 Given the name of an ethernet adapter, I need to find its IP addresses. 鉴于以太网适配器的名称,我需要找到它的IP地址。

For example, the output of ipconfig command of my system is: 例如,我系统的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

Note: I need not bother about wireless adapters or any other kind of adapters. 注意:我不必担心无线适配器或任何其他类型的适配器。 I need to do this for ethernet adapters only. 我只需要为以太网适配器执行此操作。

For this system, I need to write a Java class that behaves as shown below: 对于这个系统,我需要编写一个行为如下所示的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

What doesn't work 什么行不通

Using java.net.NetworkInterface didn't help. 使用java.net.NetworkInterface没有帮助。 It's getName() and getDisplayName() methods don't print the adapter connection names as it appears in the output of ipconfig or in Windows Network Connections. 它的getName()getDisplayName()方法不会打印出现在ipconfig输出或Windows网络连接中的适配器连接名称。 They print the actual device names instead. 它们会打印实际的设备名称。 For example, consider the following code: 例如,请考虑以下代码:

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();
        }
    }
}

This prints the following output: 这将打印以下输出:

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

An ugly hack that works 一个丑陋的黑客行事

I have written an ugly hack that extracts the IP addresses of the specified adapter name from the output of ipconfig . 我编写了一个丑陋的黑客,它从ipconfig的输出中提取指定适配器名称的IP地址。 Here is the code. 这是代码。

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);
        }
    } 
}

Question

Is there a better way to solve this problem? 有没有更好的方法来解决这个问题?

创建一个使用Windows API查询本地以太网地址并使用JNI调用dll的DLL。

I'll answer my own question. 我会回答我自己的问题。 Following SpaceTrucker's suggestion , I created a Java class using JNI as follows. 按照SpaceTrucker的建议 ,我使用JNI创建了一个Java类,如下所示。

// NwInterface.java
import java.util.ArrayList;

public class NwInterface {    

    public native ArrayList<String> getAddresses(String adapterName);    

    static
    {
        System.loadLibrary("nwinterface");
    }        
}

Then I created the 'nwinterface' library in C++ as follows. 然后我用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;
}

Finally, I tested the Java class by writing this Java program. 最后,我通过编写这个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);
        }
    }
}

The steps to compile and run the program are as follows: 编译和运行程序的步骤如下:

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

Here is the output: 这是输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM