2012-10-09 33 views
7

Problema

sistema My Windows tiene varios adaptadores de Ethernet. Dado el nombre de un adaptador de Ethernet, necesito encontrar sus direcciones IP.Obtener direcciones IPv4 de un adaptador Ethernet en Windows usando Java 1.5

Por ejemplo, la salida del comando ipconfig de mi sistema es:

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 

Nota: No necesita preocuparse acerca de los adaptadores inalámbricos o cualquier otro tipo de adaptadores. Necesito hacer esto solo para adaptadores ethernet.

Para este sistema, tengo que escribir una clase Java que se comporta como se muestra a continuación:

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 

lo que no funciona

Usando java.net.NetworkInterface no ayuda. Es getName() y getDisplayName() métodos no se imprimen los nombres de conexión del adaptador tal como aparece en la salida del ipconfig o en conexiones de red de Windows. Imprimen los nombres de los dispositivos reales en su lugar. Por ejemplo, considere el siguiente código:

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

Esto imprime el siguiente resultado:

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 

Un truco feo que funciona

He escrito un truco feo que extrae las direcciones IP de la nombre de adaptador especificado de la salida ipconfig. Aquí está el código.

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

Pregunta

¿Hay una mejor manera de resolver este problema?

+0

Parece que Java está diseñado a ser compatible Unix, Windows NIC los nombres no se han definido bien y varían según la plataforma. –

Respuesta

0

Voy a responder a mi propia pregunta. Siguiendo SpaceTrucker's suggestion, creé una clase Java usando JNI de la siguiente manera.

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

public class NwInterface {  

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

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

Luego creé la biblioteca 'nwinterface' en C++ de la siguiente manera.

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

Finalmente, probé la clase Java escribiendo este programa 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); 
     } 
    } 
} 

Los pasos para compilar y ejecutar el programa son los siguientes:

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 

Aquí está la salida:

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

Crear un DLL que utiliza la API de Windows para consultar la dirección Ethernet local y utilizar JNI para invocar la DLL.

+0

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

+0

En realidad, estaba tratando de evitar JNI, por lo que estaba explorando si podemos tener una solución pura de Java para este problema. Pero debido a la falta de respuestas a esta pregunta, parece que no hay ninguna forma pura de Java para hacer esto, así que seguí con su sugerencia e implementé una solución JNI para resolver este problema. Lo publiqué como una respuesta separada. Probablemente seleccionaré mi respuesta como la respuesta correcta para que los futuros visitantes de esta publicación puedan ver el código completo en la respuesta correcta, pero realmente aprecio su respuesta y la he votado a favor. ¡Gracias! –

+0

Me acabo de dar cuenta de que estaba pensando en direcciones MAC todo el tiempo. Pero está bien que esta respuesta también se aplique a las direcciones IPv4. – SpaceTrucker

Cuestiones relacionadas