2012-10-09 9 views
7

Problem

Mój system Windows ma wiele adapterów Ethernet. Biorąc pod uwagę nazwę adaptera ethernetowego, muszę znaleźć jego adresy IP.Uzyskaj adresy IPv4 adaptera Ethernet w systemie Windows przy użyciu języka Java 1.5

Na przykład, wyjście ipconfig rozkazu mojego systemu jest:

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 

Uwaga: Nie trzeba przejmować adapterów bezprzewodowych lub jakiegokolwiek innego rodzaju adapterów. Muszę to zrobić tylko dla kart Ethernet.

W tym systemie, muszę napisać klasy Java, który zachowuje się jak pokazano poniżej:

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 

Co nie działa

Korzystanie java.net.NetworkInterface nie pomogło. Metody te nie drukują nazw połączeń adapterów, tak jak pojawiają się na wyjściu ipconfig lub w połączeniach sieciowych systemu Windows. Zamiast tego drukują rzeczywiste nazwy urządzeń. Rozważmy na przykład następujący kod:

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

Drukuje następujące dane wyjściowe:

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 

Jest brzydki hack, który działa

Pisałem brzydki hack, który pobiera adresy IP określona nazwa adaptera z wyjścia ipconfig. Oto kod.

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

Pytanie

Czy istnieje lepszy sposób na rozwiązanie tego problemu?

+0

Wygląda Java jest zaprojektowany w byciu Unix kompatybilna, Windows NIC nazwy nie zostały dobrze zdefiniowane i różnią się w zależności od platformy. –

Odpowiedz

0

Odpowiem na moje własne pytanie. Po SpaceTrucker's suggestion utworzyłem klasę Javy, używając JNI w następujący sposób.

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

public class NwInterface {  

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

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

Następnie utworzyłem bibliotekę "nwinterface" w C++ w następujący sposób.

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

Wreszcie przetestowałem klasę Java, pisząc ten program w języku 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); 
     } 
    } 
} 

kroki, aby skompilować i uruchomić program, są następujące:

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 

Oto wynik:

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 
3

Utwórz bibliotekę dll, która używa interfejsu API systemu Windows do odpytywania lokalnego adresu ethernetowego i używania interfejsu JNI do wywołania biblioteki dll.

+0

Lub [JNA] (https://github.com/twall/jna). –

+0

Tak naprawdę próbowałem uniknąć JNI, więc zastanawiałem się, czy możemy mieć czyste rozwiązanie Javy dla tego problemu. Ale z braku odpowiedzi na to pytanie wydaje się, że nie ma żadnej czystej metody Java, aby to zrobić, więc posunąłem się naprzód z twoją sugestią i zaimplementowałem rozwiązanie JNI, aby rozwiązać ten problem. Wysłałem to jako osobną odpowiedź. Prawdopodobnie wybiorę odpowiedź jako poprawną odpowiedź, aby przyszli użytkownicy tego wpisu mogli zobaczyć kompletny kod w poprawnej odpowiedzi, ale naprawdę doceniam twoją odpowiedź i przeszedłem na jej przyjęcie. Dzięki! –

+0

Właśnie zdałem sobie sprawę, że cały czas myślałem o adresach MAC. Ale dobrze, że ta odpowiedź dotyczy również adresów IPv4. – SpaceTrucker

Powiązane problemy