2011-12-11 6 views
11

Làm cách nào để xác định giao diện mạng nào được kết nối với internet bằng Java? Ví dụ: tôi chạyCách xác định giao diện mạng Internet trong Java

InetAddress.getLocalHost().getHostAddress(); 

và trong Eclipse này trả về chính xác những gì tôi định, 192.168.1.105. Tuy nhiên, nếu tôi gói này vào một tệp jar và chạy chương trình, mã trả về 169.254.234.50. Nhìn vào đây, tôi thấy đây là địa chỉ IP của giao diện Bộ điều hợp Ethernet Ảo Ethernet trên máy của tôi.

Có cách nào để xác định giao diện được kết nối với internet, nhưng đồng thời duy trì tính di động cho mã của tôi không?

So sánh giao diện

Interface [Net4]

display name : Intel(R) Centrino(R) Ultimate-N 6300 AGN 
MTU   : 1500 
loopback  : false 
point to point: false 
up   : true 
virtual  : false 
multicast  : true 
HW address : 00 24 D7 2C 5F 70 
INET address (IPv4): 192.168.1.105 
    host name   : MyComputer 
    canonical host name : MyComputer 
    loopback   : false 
    site local   : true 
    any local   : false 
    link local   : false 
    multicast   : false 
    reachable   : true 

Interface [eth5]

display name : VMware Virtual Ethernet Adapter for VMnet1 
MTU   : 1500 
loopback  : false 
point to point: false 
up   : true 
virtual  : false 
multicast  : true 
HW address : 00 50 56 C0 00 01 
INET address (IPv4): 169.254.234.50 
    host name   : MyComputer 
    canonical host name : MyComputer 
    loopback   : false 
    site local   : false 
    any local   : false 
    link local   : true 
    multicast   : false 
    reachable   : true 

Có một giao diện VMware thứ ba với trang web địa phương = true và liên kết local = false, do đó, các trường đó sẽ xuất hiện ' t bất kỳ sự giúp đỡ nào.

+0

bạn đang chạy JAR bên trong một máy ảo VM là môi trường riêng của mình, với giao diện mạng riêng của mình, đó là? cái Java trả về. – blackcompe

+0

N o, đây là trên một máy tính Windows 7. Tôi đã cài đặt VMWare tuy nhiên, và tôi tin rằng đây là giao diện nó sử dụng để giao tiếp với máy ảo. Tôi không chắc chắn tại sao Java chọn giao diện này làm giao diện mặc định. Hành vi này giống hệt trên máy tính bạn cùng phòng của tôi (Windows 7, VMWare được cài đặt) –

+0

@CavynVonDeylen Vui lòng xem câu trả lời cập nhật của tôi. Mã tôi đã đăng chỉ in ra giao diện mạng thực của tôi, trong khi mạng của Virtual Box đã được cài đặt và kích hoạt. –

Trả lời

17

Trên máy tính xách tay của tôi (chạy Windows 7, với Hộp ảo và giao diện mạng được cài đặt) mã sau in ra tên giao diện không dây của tôi cùng với địa chỉ cục bộ của tôi. Nó sử dụng phương pháp tiếp cận vũ lực vào cuối ngày, nhưng sẽ chỉ thử và thực sự kết nối với các địa chỉ được coi là ứng cử viên tốt nhất.

// iterate over the network interfaces known to java 
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); 
OUTER : for (NetworkInterface interface_ : Collections.list(interfaces)) { 
    // we shouldn't care about loopback addresses 
    if (interface_.isLoopback()) 
    continue; 

    // if you don't expect the interface to be up you can skip this 
    // though it would question the usability of the rest of the code 
    if (!interface_.isUp()) 
    continue; 

    // iterate over the addresses associated with the interface 
    Enumeration<InetAddress> addresses = interface_.getInetAddresses(); 
    for (InetAddress address : Collections.list(addresses)) { 
    // look only for ipv4 addresses 
    if (address instanceof Inet6Address) 
     continue; 

    // use a timeout big enough for your needs 
    if (!address.isReachable(3000)) 
     continue; 

    // java 7's try-with-resources statement, so that 
    // we close the socket immediately after use 
    try (SocketChannel socket = SocketChannel.open()) { 
     // again, use a big enough timeout 
     socket.socket().setSoTimeout(3000); 

     // bind the socket to your local interface 
     socket.bind(new InetSocketAddress(address, 8080)); 

     // try to connect to *somewhere* 
     socket.connect(new InetSocketAddress("google.com", 80)); 
    } catch (IOException ex) { 
     ex.printStackTrace(); 
     continue; 
    } 

    System.out.format("ni: %s, ia: %s\n", interface_, address); 

    // stops at the first *working* solution 
    break OUTER; 
    } 
} 

(Tôi đã cập nhật câu trả lời của tôi với isReachable(...) dựa trên Mocker Tim's câu trả lời.)

Một điều cần xem ra cho.socket.bind(...) sẽ bark vào tôi rằng địa chỉ và cổng đã được sử dụng nếu tôi cố gắng chạy mã của tôi quá nhanh liên tiếp như kết nối không được làm sạch đủ nhanh. 8080 phải là một cổng ngẫu nhiên.

+0

Điều này trả về giao diện tôi muốn và hai giao diện VMWare trên máy tính của tôi. Giao diện tôi muốn là đầu tiên, nhưng tôi không thực sự muốn dựa vào đó là đúng tất cả các thời gian. –

+0

@CavynVonDeylen Nếu bạn có thể mô tả trường hợp sử dụng của bạn, chúng tôi có thể đề xuất * một số loại * giải pháp. Tuy nhiên, sẽ không có cách nào * sạch sẽ để làm điều này. Đoán đầu tiên của tôi là bạn nên lọc địa chỉ theo địa chỉ IP của họ: bỏ đi các địa chỉ * không * bắt đầu bằng '192.168.1'. Vâng, đó là * man rợ *. –

+0

Cảm ơn! Mã này làm việc cho tôi. Tôi ngạc nhiên Java không cung cấp một số cách dễ dàng để làm điều này, vì tôi nghĩ rằng đây sẽ là một vấn đề khá phổ biến. Có lẽ trong Java 8. –

5

Hãy xem Retrieving Network InterfacesListing Network Interface Addresses trong Hướng dẫn Java.

Nếu bạn có một số giao diện mạng được thiết lập và đang chạy, bạn phải chọn lập trình giao diện mạng mà chương trình của bạn nên sử dụng.

UPDATE:

tôi đã tìm thấy những câu hỏi đó là tương tự như của bạn.
Xem câu trả lời cho how-to-check-if-internet-connection-is-present-in-java.

UPDATE 2:

IMHO Bạn nên làm như sau trong chương trình của bạn:

  1. Tìm tất cả các giao diện mạng IPv4 trên máy mà chương trình bạn đang chạy trên;
  2. Yêu cầu người dùng sử dụng chương trình nào của họ;
  3. Sử dụng giao diện mà người dùng đã trỏ đến.
+1

Tôi có thể đưa ra một danh sách xa hoa của tất cả các giao diện trên máy của tôi, nhưng tôi đã không tìm thấy bất kỳ cách nào để lập trình xác định giao diện nào được kết nối với internet. Tôi giả sử rằng nếu tôi đã hardcode "net4" ví dụ, đó sẽ xảy ra là giao diện chính xác trên máy tính của tôi, điều này sẽ không giữ cho các máy tính khác chạy chương trình của tôi. –

+0

@CavynVonDeylen Xem cập nhật của tôi. – MockerTim

1

Tôi đã có cùng một vấn đề, và đã đưa ra giải pháp này (không phải là triệt để như câu trả lời, nhưng tôi cần một cái gì đó mà không cố gắng kết nối với internet.

Dựa trên OUI biết đến với mac địa chỉ: http://standards-oui.ieee.org/oui.txt

tôi đã thực hiện một kiểm tra nhanh (có thể được tối ưu hóa với logic nhị phân)

private static boolean isVmwareMac(byte[] mac) { 
    byte invalidMacs[][] = { 
      {0x00, 0x05, 0x69},    //VMWare 
      {0x00, 0x1C, 0x14},    //VMWare 
      {0x00, 0x0C, 0x29},    //VMWare 
      {0x00, 0x50, 0x56}    //VMWare 
    }; 

    for (byte[] invalid: invalidMacs){ 
     if (invalid[0] == mac[0] && invalid[1] == mac[1] && invalid[2] == mac[2]) 
      return true; 
    } 

    return false; 
}