7

問題

私の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()メソッドは、 Windowsネットワーク接続の出力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

動作する醜いハック

の出力から指定されたアダプタ名のIPアドレスを抽出する醜いハックを書きましたipconfig。これがコードです。

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

質問

この問題を解決するためのより良い方法はありますか?

4

2 に答える 2

3

Windows APIを使用してローカルイーサネットアドレスを照会するdllを作成し、JNIを使​​用してdllを呼び出します。

于 2012-10-09T14:20:53.613 に答える
0

私自身の質問に答えます。SpaceTruckerの提案に従って、次のように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
于 2012-10-09T22:54:27.210 に答える