使用Java检测互联网连接

35

可能是重复问题:
如何在Java中检查是否存在Internet连接?

我希望能够找到一种简单的方法来检测在使用Java时是否存在Internet连接。目前的应用程序在Windows上使用WinInit DLL中的“InternetGetConnectedState”方法,但我的应用程序需要跨平台支持Mac操作系统,因此这种方法将不起作用。我也不会JNI来使用Java中的DLL,这让我感到非常沮丧。

我只能想到两种方法:尝试打开与网站的URL连接,如果失败,则返回false;另外一种方法在下面,但我不知道它是否普遍稳定。当我拔掉网络电缆时,创建InetAddress时我会得到UnknownHostException。否则,如果电缆已连接,则可以获得有效的InetAddress对象。我还没有在Mac上测试下面的代码。

感谢您提供的任何示例或建议。

更新:最终代码块位于底部。我决定采纳HTTP请求(在这种情况下是Google)的建议。它很简单,发送一个请求以返回数据。如果无法从连接获取任何内容,则没有互联网连接。

public static boolean isInternetReachable()
        {
            try {

                InetAddress address = InetAddress.getByName("java.sun.com");

                if(address == null)
                {
                    return false;
                }

            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
            return true;
        }
最终代码块:
//checks for connection to the internet through dummy request
        public static boolean isInternetReachable()
        {
            try {
                //make a URL to a known source
                URL url = new URL("http://www.google.com");

                //open a connection to that source
                HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();

                //trying to retrieve data from the source. If there
                //is no connection, this line will fail
                Object objData = urlConnect.getContent();

            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
            return true;
        }
7个回答

17

这是解决问题的一个完全合理的方法。不好的一点是,你真正测试的是DNS而不是整个网络,但在实践中,你通常可以将它们视为等同的。

另一件需要记住的事情是,你需要设置一个系统属性来关闭Java运行时的DNS缓存。否则,它可能会基于缓存数据(即使它已经宕机)继续报告网络处于正常状态。

另一种方法是定期向某些网络地址发起HTTP请求。


感谢您的评论。获得反馈和不同的想法总是很好的。我曾经考虑过URL连接,或者使用HttpURLConnection。我不知道这只测试DNS,但我可能不得不接受这种方法。 - Ken
请查看上面的最终代码块并更新注意事项。 - Ken

12

需要补充的是,尽管上面给出的最终代码块很好,但它有一个缺点 - 可能要花费很长时间才能联系到指定的地址,但该地址仍然可达。

在我的实例中,当测试一个地址时,该方法会返回 true,但需要 10 秒或更长时间才能获得响应。在这种情况下,服务器是可达的,但由于连接速度太慢而没有任何有用的目的。这是因为 HttpURLConnection 的默认超时时间为0,即无限制。

出于这个原因,我建议您在 UI 线程之外执行检查,并在调用 urlConnect.getContent(); 之前加入 urlConnect.setConnectTimeout(1000);

这样你就知道地址是可达的,而且不会花费五年时间下载一个 10k 文件。

(当然,您可能希望根据自己的需求更改超时时间)

此外,我建议不要检查通用地址(如 google.com 等),除非你的程序通常访问多个域。如果只访问一个或两个域,请检查该域。


这是一个非常重要的事实需要考虑。我在虚拟机中测试应用程序时遇到了这个问题,花费了很长时间才建立连接。在这种情况下,连接超时非常关键。 - Indigo
考虑添加超时,有时可能非常重要。 - Vishrant

3
请注意,如果java.sun.com没有响应,它可能会返回false!在这种情况下,您应该检查另一个站点以确保。

好观点。我认为这个应用程序的.NET版本使用了操作系统的DLL。这样,操作系统可以立即知道是否有连接,而不是对网站进行ping或检查流。它会在什么时候提出问题。一个网站后?两个?这正是我想要的输入。 - Ken

2
第一种解决方案的问题在于InetAddress具有缓存机制,因此,当您在接下来的几次调用中失去连接时,名称将通过java缓存进行解析。使用URL连接方法时,存在使用getContent获取html的问题,因此会产生数据消耗。如果频繁调用可能会成为问题(特别是如果运行软件的设备没有无限的数据计划)。
我认为最好的解决方案是对80端口进行TCP连接并在成功连接后立即关闭。这将与最终代码具有相同的行为,但流量要少得多。

2

我建议查看java.net.NetworkInterface.getNetworkInterfaces()。这将返回机器上所有网络接口的枚举,如果没有则返回null。

我不确定是否安全地假设非空响应确保有效的网络连接 - 根据您的需求,您可能需要过滤掉环回地址(我认为您可以在每个返回的NetworkInterface上使用java.net.NetworkInterface.getInetAddresses(),然后在每个上调用InetAddress.isLoopbackAddress())。


2
唯一确保能够访问特定服务的方法是向该服务发送虚拟请求。Ping可能会被防火墙屏蔽。有些服务器可以访问,而其他服务器则无法访问。如果需要与Web服务通信,请准备一个静态页面用于响应这些请求。
此外,在尝试联系之前,记得先询问用户。

你唯一能够确定的方法就是执行真实请求。在真正的请求前进行虚拟请求可能会失败,进而导致真实请求成功,或者反之。未来是无法预测的。 - user207421

1
这个问题实际上没有意义。'连接到互联网'并不存在。你必须尝试去创建一个连接。Windows API只是告诉你你的调制解调器是否已经拨号成功,我曾经看到它实际上导致了拨号,这不是我们想要的结果。虽然我已经有8年没有使用拨号了。

这并不是对问题的回答。如果要批评或请求作者澄清,请在他们的帖子下留言。 - Ian Lim
1
@IanLim 这里给出的答案是“你必须尝试创建一个”,并且与大多数其他答案一致。 - user207421

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