使用Java获取当前计算机的IP地址

344

我正在尝试开发一个系统,其中有不同的节点在不同的系统或同一系统的不同端口上运行。

现在,所有节点都会创建一个Socket,其中目标IP是称为引导节点的特殊节点的IP。然后,节点创建自己的ServerSocket并开始侦听连接。

引导节点维护节点列表,并在查询时返回它们。

现在我需要的是,节点必须向引导节点注册其IP。我尝试使用cli.getInetAddress()一旦客户端连接到引导节点的ServerSocket,但那行不通。

  1. 如果PPP IP可用,则需要客户端注册其PPP IP;
  2. 否则,如果可用,则需要注册LAN IP;
  3. 否则,假定注册127.0.0.1表示它与相同计算机。

使用的代码:

System.out.println(Inet4Address.getLocalHost().getHostAddress());
或者
System.out.println(InetAddress.getLocalHost().getHostAddress());

我的PPP连接IP地址是:117.204.44.192,但是上面的代码返回给我192.168.1.2。

编辑

我正在使用以下代码:

Enumeration e = NetworkInterface.getNetworkInterfaces();
while(e.hasMoreElements())
{
    NetworkInterface n = (NetworkInterface) e.nextElement();
    Enumeration ee = n.getInetAddresses();
    while (ee.hasMoreElements())
    {
        InetAddress i = (InetAddress) ee.nextElement();
        System.out.println(i.getHostAddress());
    }
}

我能够获取所有与NetworkInterface相关联的IP地址,但如何区分它们?这是我得到的输出:

127.0.0.1
192.168.1.2
192.168.56.1
117.204.44.19

3
如果我在循环内部添加 n.isPointToPoint(),这样会起作用吗?我的想法是,如果没有找到点对点网络,则返回“127.0.0.1”。这样行得通吗? - sasidhar
3
请勿张贴您的真实IP地址。对于私人IP,请写117.xxx.xxx.xxx,这是可以接受的。 - nIcE cOw
@sattu 内部的 while 循环是为了获取绑定到此特定 NetworkInterface 的所有 InetAddresses。一个网络接口可能与一个或多个 InetAddresses 相关联。 - sasidhar
@sattu 在 Linux 发行版上尝试 ifconfig -a 命令。然后你就能看到什么是“网络接口”了。那个循环迭代这些接口。 - jilen
2
相关:https://dev59.com/l2025IYBdhLWcg3wVkif - AlikElzin-kilaka
显示剩余3条评论
19个回答

4
这是上面被接受的答案的一个可行示例!这个NetIdentity类将存储内部主机IP和本地环回。如果您在基于DNS的服务器上,如上所述,您可能需要添加一些更多的检查,或者可能使用配置文件路线。
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;

/**
 * Class that allows a device to identify itself on the INTRANET.
 * 
 * @author Decoded4620 2016
 */
public class NetIdentity {

    private String loopbackHost = "";
    private String host = "";

    private String loopbackIp = "";
    private String ip = "";
    public NetIdentity(){

        try{
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();

            while(interfaces.hasMoreElements()){
                NetworkInterface i = interfaces.nextElement();
                if(i != null){
                    Enumeration<InetAddress> addresses = i.getInetAddresses();
                    System.out.println(i.getDisplayName());
                    while(addresses.hasMoreElements()){
                        InetAddress address = addresses.nextElement();
                        String hostAddr = address.getHostAddress();

                        // local loopback
                        if(hostAddr.indexOf("127.") == 0 ){
                            this.loopbackIp = address.getHostAddress();
                            this.loopbackHost = address.getHostName();
                        }

                        // internal ip addresses (behind this router)
                        if( hostAddr.indexOf("192.168") == 0 || 
                                hostAddr.indexOf("10.") == 0 || 
                                hostAddr.indexOf("172.16") == 0 ){
                            this.host = address.getHostName();
                            this.ip = address.getHostAddress();
                        }


                        System.out.println("\t\t-" + address.getHostName() + ":" + address.getHostAddress() + " - "+ address.getAddress());
                    }
                }
            }
        }
        catch(SocketException e){

        }
        try{
            InetAddress loopbackIpAddress = InetAddress.getLocalHost();
            this.loopbackIp = loopbackIpAddress.getHostName();
            System.out.println("LOCALHOST: " + loopbackIp);
        }
        catch(UnknownHostException e){
            System.err.println("ERR: " + e.toString());
        }
    }

    public String getLoopbackHost(){
        return loopbackHost;
    }

    public String getHost(){
        return host;
    }
    public String getIp(){
        return ip;
    }
    public String getLoopbackIp(){
        return loopbackIp;
    }
}

当我运行这段代码时,实际上会得到这样的输出:
    Software Loopback Interface 1
        -127.0.0.1:127.0.0.1 - [B@19e1023e
        -0:0:0:0:0:0:0:1:0:0:0:0:0:0:0:1 - [B@7cef4e59
Broadcom 802.11ac Network Adapter
        -VIKING.yourisp.com:192.168.1.142 - [B@64b8f8f4
        -fe80:0:0:0:81fa:31d:21c9:85cd%wlan0:fe80:0:0:0:81fa:31d:21c9:85cd%wlan0 - [B@2db0f6b2
Microsoft Kernel Debug Network Adapter
Intel Edison USB RNDIS Device
Driver for user-mode network applications
Cisco Systems VPN Adapter for 64-bit Windows
VirtualBox Host-Only Ethernet Adapter
        -VIKING:192.168.56.1 - [B@3cd1f1c8
        -VIKING:fe80:0:0:0:d599:3cf0:5462:cb7%eth4 - [B@3a4afd8d
LogMeIn Hamachi Virtual Ethernet Adapter
        -VIKING:25.113.118.39 - [B@1996cd68
        -VIKING:2620:9b:0:0:0:0:1971:7627 - [B@3339ad8e
        -VIKING:fe80:0:0:0:51bf:994d:4656:8486%eth5 - [B@555590
Bluetooth Device (Personal Area Network)
        -fe80:0:0:0:4c56:8009:2bca:e16b%eth6:fe80:0:0:0:4c56:8009:2bca:e16b%eth6 - [B@3c679bde
Bluetooth Device (RFCOMM Protocol TDI)
Intel(R) Ethernet Connection (2) I218-V
        -fe80:0:0:0:4093:d169:536c:7c7c%eth7:fe80:0:0:0:4093:d169:536c:7c7c%eth7 - [B@16b4a017
Microsoft Wi-Fi Direct Virtual Adapter
        -fe80:0:0:0:103e:cdf0:c0ac:1751%wlan1:fe80:0:0:0:103e:cdf0:c0ac:1751%wlan1 - [B@8807e25
VirtualBox Host-Only Ethernet Adapter-HHD Software NDIS 6.0 Filter Driver-0000
VirtualBox Host-Only Ethernet Adapter-WFP Native MAC Layer LightWeight Filter-0000
VirtualBox Host-Only Ethernet Adapter-HHD Software NDIS 6.0 Filter Driver-0001
VirtualBox Host-Only Ethernet Adapter-HHD Software NDIS 6.0 Filter Driver-0002
VirtualBox Host-Only Ethernet Adapter-VirtualBox NDIS Light-Weight Filter-0000
VirtualBox Host-Only Ethernet Adapter-HHD Software NDIS 6.0 Filter Driver-0003
VirtualBox Host-Only Ethernet Adapter-QoS Packet Scheduler-0000
VirtualBox Host-Only Ethernet Adapter-HHD Software NDIS 6.0 Filter Driver-0004
VirtualBox Host-Only Ethernet Adapter-WFP 802.3 MAC Layer LightWeight Filter-0000
VirtualBox Host-Only Ethernet Adapter-HHD Software NDIS 6.0 Filter Driver-0005
Intel(R) Ethernet Connection (2) I218-V-HHD Software NDIS 6.0 Filter Driver-0000
Intel(R) Ethernet Connection (2) I218-V-WFP Native MAC Layer LightWeight Filter-0000
Intel(R) Ethernet Connection (2) I218-V-HHD Software NDIS 6.0 Filter Driver-0001
Intel(R) Ethernet Connection (2) I218-V-Shrew Soft Lightweight Filter-0000
Intel(R) Ethernet Connection (2) I218-V-HHD Software NDIS 6.0 Filter Driver-0002
Intel(R) Ethernet Connection (2) I218-V-VirtualBox NDIS Light-Weight Filter-0000
Intel(R) Ethernet Connection (2) I218-V-HHD Software NDIS 6.0 Filter Driver-0003
Intel(R) Ethernet Connection (2) I218-V-QoS Packet Scheduler-0000
Intel(R) Ethernet Connection (2) I218-V-HHD Software NDIS 6.0 Filter Driver-0004
Intel(R) Ethernet Connection (2) I218-V-WFP 802.3 MAC Layer LightWeight Filter-0000
Intel(R) Ethernet Connection (2) I218-V-HHD Software NDIS 6.0 Filter Driver-0005
Broadcom 802.11ac Network Adapter-WFP Native MAC Layer LightWeight Filter-0000
Broadcom 802.11ac Network Adapter-Virtual WiFi Filter Driver-0000
Broadcom 802.11ac Network Adapter-Native WiFi Filter Driver-0000
Broadcom 802.11ac Network Adapter-HHD Software NDIS 6.0 Filter Driver-0003
Broadcom 802.11ac Network Adapter-Shrew Soft Lightweight Filter-0000
Broadcom 802.11ac Network Adapter-HHD Software NDIS 6.0 Filter Driver-0004
Broadcom 802.11ac Network Adapter-VirtualBox NDIS Light-Weight Filter-0000
Broadcom 802.11ac Network Adapter-HHD Software NDIS 6.0 Filter Driver-0005
Broadcom 802.11ac Network Adapter-QoS Packet Scheduler-0000
Broadcom 802.11ac Network Adapter-HHD Software NDIS 6.0 Filter Driver-0006
Broadcom 802.11ac Network Adapter-WFP 802.3 MAC Layer LightWeight Filter-0000
Broadcom 802.11ac Network Adapter-HHD Software NDIS 6.0 Filter Driver-0007
Microsoft Wi-Fi Direct Virtual Adapter-WFP Native MAC Layer LightWeight Filter-0000
Microsoft Wi-Fi Direct Virtual Adapter-Native WiFi Filter Driver-0000
Microsoft Wi-Fi Direct Virtual Adapter-HHD Software NDIS 6.0 Filter Driver-0002
Microsoft Wi-Fi Direct Virtual Adapter-Shrew Soft Lightweight Filter-0000
Microsoft Wi-Fi Direct Virtual Adapter-HHD Software NDIS 6.0 Filter Driver-0003
Microsoft Wi-Fi Direct Virtual Adapter-VirtualBox NDIS Light-Weight Filter-0000
Microsoft Wi-Fi Direct Virtual Adapter-HHD Software NDIS 6.0 Filter Driver-0004
Microsoft Wi-Fi Direct Virtual Adapter-QoS Packet Scheduler-0000
Microsoft Wi-Fi Direct Virtual Adapter-HHD Software NDIS 6.0 Filter Driver-0005
Microsoft Wi-Fi Direct Virtual Adapter-WFP 802.3 MAC Layer LightWeight Filter-0000
Microsoft Wi-Fi Direct Virtual Adapter-HHD Software NDIS 6.0 Filter Driver-0006

对于我的使用,我正在设置一个Upnp服务器,理解我所寻找的“模式”非常有帮助。返回的一些对象是以太网适配器、网络适配器、虚拟网络适配器、驱动程序和VPN客户端适配器。并不是所有的对象都有地址。因此,你需要跳过那些没有接口的对象。
你还可以将此添加到当前的NetworkInterface i循环中。
while(interfaces.hasMoreElements()){
    Enumeration<InetAddress> addresses = i.getInetAddresses();
    System.out.println(i.getDisplayName());
    System.out.println("\t- name:" + i.getName());
    System.out.println("\t- idx:" + i.getIndex());
    System.out.println("\t- max trans unit (MTU):" + i.getMTU());
    System.out.println("\t- is loopback:" + i.isLoopback());
    System.out.println("\t- is PPP:" + i.isPointToPoint());
    System.out.println("\t- isUp:" + i.isUp());
    System.out.println("\t- isVirtual:" + i.isVirtual());
    System.out.println("\t- supportsMulticast:" + i.supportsMulticast());
}

您将在输出中看到类似以下信息的内容:

接下来是需要翻译的内容:

Software Loopback Interface 1
    - name:lo
    - idx:1
    - max trans unit (MTU):-1
    - is loopback:true
    - is PPP:false
    - isUp:true
    - isVirtual:false
    - supportsMulticast:true
        -ADRESS: [127.0.0.1(VIKING-192.168.56.1)]127.0.0.1:127.0.0.1 - [B@19e1023e
        -ADRESS: [0:0:0:0:0:0:0:1(VIKING-192.168.56.1)]0:0:0:0:0:0:0:1:0:0:0:0:0:0:0:1 - [B@7cef4e59
Broadcom 802.11ac Network Adapter
    - name:wlan0
    - idx:2
    - max trans unit (MTU):1500
    - is loopback:false
    - is PPP:false
    - isUp:true
    - isVirtual:false
    - supportsMulticast:true
        -ADRESS: [VIKING.monkeybrains.net(VIKING-192.168.56.1)]VIKING.monkeybrains.net:192.168.1.142 - [B@64b8f8f4
        -ADRESS: [fe80:0:0:0:81fa:31d:21c9:85cd%wlan0(VIKING-192.168.56.1)]fe80:0:0:0:81fa:31d:21c9:85cd%wlan0:fe80:0:0:0:81fa:31d:21c9:85cd%wlan0 - [B@2db0f6b2
Microsoft Kernel Debug Network Adapter
    - name:eth0
    - idx:3
    - max trans unit (MTU):-1
    - is loopback:false
    - is PPP:false
    - isUp:false
    - isVirtual:false
    - supportsMulticast:true

3

使用InetAddress.getLocalHost()获取本地地址。

import java.net.InetAddress;

try {
  InetAddress addr = InetAddress.getLocalHost();            
  System.out.println(addr.getHostAddress());
} catch (UnknownHostException e) {
}

我的PPP连接IP地址是:117.204.44.192,但以上返回给我192.168.1.2。 - sasidhar
你需要爬取所有可用的 InetAddress 实例,并找出哪一个是正确的。 - Decoded
冗余的答案:https://dev59.com/IGkx5IYBdhLWcg3wCP-Y#25257429 说了同样的事情。 - Stephen C

2
您的计算机可以拥有多个NetworkInterface,每个接口都有多个InetAddress。如果您过滤掉任何本地地址,则剩余的地址是非本地地址,其中您可以拥有一个、零个或多个。
不幸的是,Java中的网络API仍然使用(旧)枚举而不是迭代器和流,我们可以通过将它们包装为流来对其进行处理。所以我们需要做的就是:
  • 遍历所有网络接口及其地址,并
  • 过滤掉本地的地址
代码:
private Stream<InetAddress> getNonLocalIpAddresses() throws IOException {
    return enumerationAsStream(NetworkInterface.getNetworkInterfaces())
        .flatMap(networkInterface -> enumerationAsStream(networkInterface.getInetAddresses()))
        .filter(inetAddress -> !inetAddress.isAnyLocalAddress())
        .filter(inetAddress -> !inetAddress.isSiteLocalAddress())
        .filter(inetAddress -> !inetAddress.isLoopbackAddress())
        .filter(inetAddress -> !inetAddress.isLinkLocalAddress());
}

在我的机器上,这当前返回两个IPv6地址。
要获取这些InetAdresses中的第一个,请执行以下操作:
private String getMyIp() throws IOException {
    return getNonLocalIpAddresses()
        .map(InetAddress::getHostAddress)
        .findFirst()
        .orElseThrow(NoSuchElementException::new);
}

将枚举包装为流的方法:

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
            new Iterator<>() {
                public T next() { return e.nextElement();  }
                public boolean hasNext() { return e.hasMoreElements(); }
            }, Spliterator.ORDERED), false);
}

1

一种相对简单的方法,似乎很有效...

String getPublicIPv4() throws UnknownHostException, SocketException{
    Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
    String ipToReturn = null;
    while(e.hasMoreElements())
    {
        NetworkInterface n = (NetworkInterface) e.nextElement();
        Enumeration<InetAddress> ee = n.getInetAddresses();
        while (ee.hasMoreElements())
        {
            InetAddress i = (InetAddress) ee.nextElement();
            String currentAddress = i.getHostAddress();
            logger.trace("IP address "+currentAddress+ " found");
            if(!i.isSiteLocalAddress()&&!i.isLoopbackAddress() && validate(currentAddress)){
                ipToReturn = currentAddress;    
            }else{
                System.out.println("Address not validated as public IPv4");
            }

        }
    }

    return ipToReturn;
}

private static final Pattern IPv4RegexPattern = Pattern.compile(
        "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");

public static boolean validate(final String ip) {
    return IPv4RegexPattern.matcher(ip).matches();
}

1
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

public class IpAddress {

NetworkInterface ifcfg;
Enumeration<InetAddress> addresses;
String address;

public String getIpAddress(String host) {
    try {
        ifcfg = NetworkInterface.getByName(host);
        addresses = ifcfg.getInetAddresses();
        while (addresses.hasMoreElements()) {
            address = addresses.nextElement().toString();
            address = address.replace("/", "");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return ifcfg.toString();
}
}

0
一个 Kotlin 的例子,至少在 Windows 上可以工作,即使我的 VPN 打开了。 (其他方法在 VPN 打开时似乎都失败了) 它涉及到只查找一次计算机的 IP 地址。从那时起,IP 地址始终可以从存储的适配器信息中找到。
import java.net.NetworkInterface
import java.util.prefs.Preferences

class WindowsIP {
    companion object {
        val prefs = Preferences.userNodeForPackage(this::class.java)  //Get the current IP address for the wifi adapter whose information
        // has been stored by calling findWifiAdapter(currentIp) with the known current IP (from wifi properties or whatever)
        fun getIpAddress(): String {
            val wlanName = prefs.get("WlanName", "")
            val wlanDisplName = prefs.get("WlanDisplName", "")
            val addrCnt = prefs.getInt("wlanAddrCount", 0)
            val nis = NetworkInterface.getNetworkInterfaces()
            for (ni in nis) {
                if (ni.name == wlanName && ni.displayName == wlanDisplName) {
                    var count = 0
                    for (addr in ni.inetAddresses) {
                        if (count++ == addrCnt) {
                            return addr.hostAddress
                        }
                    }
                }
            }
            return "Unknown. Call findWifiAdapter() with current IP address"
        }

        fun findWifiAdapter(currentIP: String) {  //Find the wifi adapter using the current IP address and store the information
                val nis = NetworkInterface.getNetworkInterfaces()
                for(ni in nis) {
                    var count = 0;
                    for(adr in ni.inetAddresses) {
                        if(adr.hostAddress == currentIP) {
                            prefs.put("WlanName", ni.name)
                            prefs.put("WlanDisplName", ni.displayName)
                            prefs.putInt("wlanAddrCount", count)  //Probably always zero?
                        }
                        ++count
                    }
                }
        }
    }
}

0

由于我的系统(就像许多其他系统一样)具有各种网络接口。InetAddress.getLocalHost()Inet4Address.getLocalHost()只是返回了我不需要的一个接口。 因此,我不得不使用这种天真的方法。

InetAddress[] allAddresses = Inet4Address.getAllByName("YourComputerHostName");
        InetAddress desiredAddress;
        //In order to find the desired Ip to be routed by other modules (WiFi adapter)
        for (InetAddress address :
                allAddresses) {
            if (address.getHostAddress().startsWith("192.168.2")) {
                desiredAddress = address;
            }
        }
// Use the desired address for whatever purpose.

只要注意,在这种方法中,我已经知道我的所需IP地址属于192.168.2子网。


0

如果您的计算机是网络的一部分,此代码将获取您的网络IP地址。

try {
    System.out.println(InetAddress.getLocalHost().getHostAddress());
} catch (UnknownHostException e) {
    e.printStackTrace();
}

答案重复了。其他(更早的)答案已经说了同样的事情。 - Stephen C

0
通常当我尝试查找我的公共IP地址,比如cmyip.com或者www.iplocation.net,我会使用以下方法:
public static String myPublicIp() {

    /*nslookup myip.opendns.com resolver1.opendns.com*/
    String ipAdressDns  = "";
    try {
        String command = "nslookup myip.opendns.com resolver1.opendns.com";
        Process proc = Runtime.getRuntime().exec(command);

        BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));

        String s;
        while ((s = stdInput.readLine()) != null) {
            ipAdressDns  += s + "\n";
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    return ipAdressDns ;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接