在 Java 中获取“外部”IP 地址

Posted

技术标签:

【中文标题】在 Java 中获取“外部”IP 地址【英文标题】:Getting the 'external' IP address in Java 【发布时间】:2011-02-25 17:20:20 【问题描述】:

我不太清楚如何获取机器的外部 IP 地址,因为网络外部的计算机会看到它。

我下面的 IPAddress 类只获取机器的本地 IP 地址。

public class IPAddress 

    private InetAddress thisIp;

    private String thisIpAddress;

    private void setIpAdd() 
        try 
            InetAddress thisIp = InetAddress.getLocalHost();
            thisIpAddress = thisIp.getHostAddress().toString();
         catch (Exception e) 
        
    

    protected String getIpAddress() 
        setIpAdd();
        return thisIpAddress;
    

【问题讨论】:

您知道一台机器可以同时拥有多个公共地址吗?它们实际上与网络接口相关联,而不是与机器相关联。 【参考方案1】:

我不确定您是否可以从本地机器上运行的代码中获取该 IP。

但是,您可以构建在网站上运行的代码,比如在 JSP 中,然后使用返回请求来源 IP 的东西:

request.getRemoteAddr()

或者简单地使用已经存在的服务,然后从服务中解析答案以找出 IP。

使用 AWS 等网络服务

import java.net.*;
import java.io.*;

URL whatismyip = new URL("http://checkip.amazonaws.com");
BufferedReader in = new BufferedReader(new InputStreamReader(
                whatismyip.openStream()));

String ip = in.readLine(); //you get the IP as a String
System.out.println(ip);

【讨论】:

警告:他们已将自动化 URL 调整为 automation.whatismyip.com/n09230945.asp 我建议至少实施两台为您的 ip 提供服务的服务器,以防其中一台此时出现故障(当然要进行正确的错误处理)。我的选择是externalip.net(单击“需要 API?”链接)。已经使用该网站一年多了,到目前为止还没有遇到任何问题,而且它是一项快速的服务,总是能快速响应。 很棒的链接;我将把它用作大学网络任务概念证明的一部分! 另一种选择是,如果您可以访问运行 php 的 Web 服务器或主机帐户,只需使用上面提供的代码 @bakkal 并将其指向您自己的仅包含 echo $_SERVER['REMOTE_ADDR']; 的 PHP 文件。如果这是脚本的唯一或第一行输出,则一切就绪。 Whatsmyip.com 似乎不再支持这种类型的自动化。【参考方案2】:

@stivlo 的其中一个 cmets 值得回答:

您可以使用亚马逊服务http://checkip.amazonaws.com

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;

public class IpChecker 

    public static String getIp() throws Exception 
        URL whatismyip = new URL("http://checkip.amazonaws.com");
        BufferedReader in = null;
        try 
            in = new BufferedReader(new InputStreamReader(
                    whatismyip.openStream()));
            String ip = in.readLine();
            return ip;
         finally 
            if (in != null) 
                try 
                    in.close();
                 catch (IOException e) 
                    e.printStackTrace();
                
            
        
    

【讨论】:

【参考方案3】:

事实是:从您提出问题的意义上说,“您不能”。 NAT 发生在协议之外。您的机器内核无法知道您的 NAT 盒子是如何从外部 IP 地址映射到内部 IP 地址的。此处的其他答案提供了一些技巧,涉及与外部网站对话的方法。

【讨论】:

还是不行,因为它没有回答原始问题,而且看起来像是一个学术练习 公平地说,这个答案确实回答了这个问题,而其他十几个答案基本上都说了同样的话,但显示了特定于任何给定外部 ip 检查器选择的代码或 URL。【参考方案4】:

所有这些仍然正常运行! (截至 2022 年 2 月 10 日)

http://checkip.amazonaws.com/ https://ipv4.icanhazip.com/ http://myexternalip.com/raw http://ipecho.net/plain http://www.trackip.net/ip http://bot.whatismyipaddress.com(2022 年 2 月 10 日) http://curlmyip.com/(2016 年 12 月 17 日)

忠告:不要直接依赖其中一个;尝试使用一个,但有一个考虑到其他人的应急计划!用得越多越好!

祝你好运!

【讨论】:

【参考方案5】:

正如@Donal Fellows 所写,您必须查询网络接口而不是机器。 javadocs 中的这段代码对我有用:

以下示例程序列出了机器上的所有网络接口及其地址:

import java.io.*;
import java.net.*;
import java.util.*;
import static java.lang.System.out;

public class ListNets 

    public static void main(String args[]) throws SocketException 
        Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
        for (NetworkInterface netint : Collections.list(nets))
            displayInterfaceInformation(netint);
    

    static void displayInterfaceInformation(NetworkInterface netint) throws SocketException 
        out.printf("Display name: %s\n", netint.getDisplayName());
        out.printf("Name: %s\n", netint.getName());
        Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
        for (InetAddress inetAddress : Collections.list(inetAddresses)) 
            out.printf("InetAddress: %s\n", inetAddress);
        
        out.printf("\n");
     
 

以下是示例程序的示例输出:

Display name: TCP Loopback interface
Name: lo
InetAddress: /127.0.0.1

Display name: Wireless Network Connection
Name: eth0
InetAddress: /192.0.2.0

来自docs.oracle.com

【讨论】:

谢谢!虽然该解决方案在软件位于 NAT 之后时不起作用,但它对于您知道不会位于 NAT 之后的服务器软件仍然非常有帮助,或者如果软件无法连接到另一台服务器以获得它自己的服务器,它仍然非常有用知识产权。特别是对于打算在与 Internet 断开连接的 LAN 上运行的软件,这是可行的方法。【参考方案6】:

创建一个到 www.whatismyip.com 之类的网站的 HttpURLConnection 并解析它:-)

【讨论】:

【参考方案7】:

这个怎么样?这很简单,对我来说效果最好:)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;


public class IP 
    public static void main(String args[]) 
        new IP();
    

    public IP() 
        URL ipAdress;

        try 
            ipAdress = new URL("http://myexternalip.com/raw");

            BufferedReader in = new BufferedReader(new InputStreamReader(ipAdress.openStream()));

            String ip = in.readLine();
            System.out.println(ip);
         catch (MalformedURLException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
        
    

【讨论】:

这太棒了!我回家后会试试的。这正是我一直在寻找的解决问题的方法。不知道为什么它没有被投票更高。【参考方案8】:

http://jstun.javawi.de/ 会做 - 只要你的网关设备做 STUN )大多数做)

【讨论】:

非常有趣,它按预期工作,无需使用外部服务,只需与网关对话。然而,GPL 许可可能会限制其采用。 网站给了我一个登录屏幕。可能不是原版。【参考方案9】:

这并不容易,因为局域网内的机器通常不关心其路由器到互联网的外部 IP。它根本不需要它!

我建议您通过打开类似http://www.whatismyip.com/ 的网站并通过解析 html 结果获取 IP 号来利用此功能。这应该不难!

【讨论】:

您不必解析 html。 whatismyip.com的网页来源第一行就是你的外网IP。【参考方案10】:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.regex.Pattern;

public class ExternalIPUtil 

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

    private static final String[] IPV4_SERVICES = 
            "http://checkip.amazonaws.com/",
            "https://ipv4.icanhazip.com/",
            "http://bot.whatismyipaddress.com/"
            // and so on ...
    ;

    public static String get() throws ExecutionException, InterruptedException 
        List<Callable<String>> callables = new ArrayList<>();
        for (String ipService : IPV4_SERVICES) 
            callables.add(() -> get(ipService));
        

        ExecutorService executorService = Executors.newCachedThreadPool();
        try 
            return executorService.invokeAny(callables);
         finally 
            executorService.shutdown();
        
    

    private static String get(String url) throws IOException 
        try (BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) 
            String ip = in.readLine();
            if (IPV4_PATTERN.matcher(ip).matches()) 
                return ip;
             else 
                throw new IOException("invalid IPv4 address: " + ip);
            
        
    

    public static void main(String[] args) throws ExecutionException, InterruptedException 
        System.out.println("IP: " + get());
    

同时从多个 IP 服务获取,例如:

http://checkip.amazonaws.com/ https://ipv4.icanhazip.com/ http://bot.whatismyipaddress.com/ 等等...

ExecutorService.invokeAny(tasks) 返回第一个成功线程的结果。其他未完成的任务将被取消。

【讨论】:

【参考方案11】:

如果您使用的是基于 JAVA 的 webapp,并且如果您想获取客户端(通过浏览器发出请求的人)的外部 ip,请尝试在 公共域 中部署该应用并使用 request.getRemoteAddr () 读取外部 IP 地址。

【讨论】:

【参考方案12】:
System.out.println(pageCrawling.getHtmlFromURL("http://ipecho.net/plain"));

【讨论】:

【参考方案13】:

另一种解决方案是执行外部命令,显然,这种解决方案限制了应用程序的可移植性。

例如,对于在 Windows 上运行的应用程序,可以通过 jPowershell 执行 PowerShell 命令,如下代码所示:

public String getMyPublicIp() 
    // PowerShell command
    String command = "(Invoke-WebRequest ifconfig.me/ip).Content.Trim()";
    String powerShellOut = PowerShell.executeSingleCommand(command).getCommandOutput();

    // Connection failed
    if (powerShellOut.contains("InvalidOperation")) 
        powerShellOut = null;
    
    return powerShellOut;

【讨论】:

以上是关于在 Java 中获取“外部”IP 地址的主要内容,如果未能解决你的问题,请参考以下文章

LogParser 查询仅从 IIS 日志中获取外部 IP 地址?

在 C# 中通过远程处理获取外部 IP 地址

您可以从 Google Compute VM 实例中获取外部 IP 地址吗?

如何从 STUN 请求中获取我的外部 IP 地址和外部端口号?

获取机器公网IP

Qt 使用 QNetworkReply 获取外部 IP 地址