如何在不使用外部主机的情况下以编程方式查找设备的外部 IP 地址?

Posted

技术标签:

【中文标题】如何在不使用外部主机的情况下以编程方式查找设备的外部 IP 地址?【英文标题】:How to programmatically find the external IP address of a device without using external host? 【发布时间】:2014-09-08 08:20:51 【问题描述】:

当我读取设备的 IP 地址时,我总是得到本地 IP 地址。

我使用下面的代码 sn-p 来做到这一点。

public String getIpAddress() 
   try 
         for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) 
                NetworkInterface intf = en.nextElement();
             for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) 
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress()) 
                        String ip = Formatter.formatIpAddress(inetAddress.hashCode());
                        Log.d("***Connected",ip);
                        return ip;
                    
                
            

         catch (Exception ex) 
            Log.d("exception", ex.toString());
        
        return "EMPTY";
    

但我需要读取外部 IP 地址,而不使用任何外部主机或 Web api,例如 http://jsonip.com

【问题讨论】:

我不知道这对于任何环境都是可能的,更不用说android了。您不知道您和外界之间有多少 NAT、防火墙、代理等。 @CommonsWare 我们可以使用类似 traceroute 的逻辑并寻找第一个“真实世界”IP 吗? 要使用 traceroute,您需要一个尝试跟踪路由的外部主机。然后,您需要自己的算法来确定“真实世界 IP”是什么。 @CommonsWare 然后我们将不得不寻找替代解决方案。 @CommonsWare 仅供参考:我们有一个 SDN 解决方案,可以根据需求阻止任何域。这就是为什么我不想在此过程中包含任何外部主机 【参考方案1】:

大多数回复都是完全正确的。最好的办法是让您连接到一个外部服务,该服务使用您的公共 IP 地址回复。但是,您不想连接到外部服务是有原因的(1)您只是不想运行自己的服务或为某些 3rd 方服务付费,以及(2)您的应用程序应该以“隐形”模式运行并且不是时不时联系互联网上的一些服务。

但是,您可以做的是依赖 100% 纯 Java 跟踪路由实现,例如此处介绍的实现:http://people.dsv.su.se/~miko1432/ip/ip1/4.3/doc/_traceroute_8java_source.html

通过连接到 traceroute 实现,您可以在通往 Internet 的路径上一个接一个地 ping 一个主机。基本上这样你就可以“ping”任意公共 IP 地址并查看到达目的地的路由。

如果您查看跟踪,您将看到私有(非路由)IP 地址,例如网络 192.168.0.0/16 和 10.0.0.0/8 中的 IP 地址。您可以放心地假设这些是私有地址,并且您路由上的第一个公共 IP 地址是您的公共 IP 地址。

这也适用于为客户端设备分配公共 IP 地址的情况,例如某些移动运营商或学术网络的情况。

【讨论】:

我不想使用 web api 获取 IP 地址的原因是需要相当长的时间。你能给我一个代码 sn-p 吗?

以上是关于如何在不使用外部主机的情况下以编程方式查找设备的外部 IP 地址?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用命令的情况下以编程方式关闭/重启 linux 机器(运行时)

如何在不使用第三方的情况下以编程方式从 Chase 下载我的银行交易?

如何在不使用 HTML 表单的情况下以编程方式将 POST 请求发送到 JSF 页面?

如何在不使用 Facebook 登录/注销按钮的情况下以编程方式从 Facebook SDK 3.0 注销?

如何在不使用 rest admin api 的情况下以编程方式(java)更新 keycloak 的用户详细信息?

如何在不编码窗口状态的情况下以编程方式终止 NSApp?