如何用Java检查当前是否有网络连接?

72

如何通过Java检查是否可以连接到互联网?一种方法是:

final URL url = new URL("http://www.google.com");
final URLConnection conn = url.openConnection();
... if we got here, we should have net ...

但是有没有更适合执行这项任务的东西,特别是如果您需要经常进行连续检查,而且失去互联网连接的可能性非常高?


答案与许多其他相同形式的问题的答案相同。确定任何资源是否可用的唯一正确方法是在正常执行过程中尝试使用它,并在发生故障时进行处理。任何其他技术都是一种或另一种尝试预测未来的形式。 - user207421
18个回答

56

你应该连接到你实际应用程序需要的地方,否则就是在测试你是否与某个不相关的地方(比如这里的 Google)建立了连接。

特别是,如果你正在尝试与一个 Web 服务交互,并且如果你控制着这个 Web 服务,那么最好有一些廉价的“获取状态”的 Web 方法。这样你就可以更好地知道你的“真实”调用是否有可能成功。

在其他情况下,仅仅打开应该开放的端口或发送一个 ping 可能就足够了。在这里,InetAddress.isReachable API 可能是一个合适的选择。


3
isReachable的链接指向了错误的类。正确的链接为 http://java.sun.com/javase/6/docs/api/java/net/InetAddress.html#isReachable。 - Chris Mazzola
19
如果您连接到想要通信的资源失败了,该如何知道是目标服务器的问题,还是因为没有互联网连接?因此,“连接到您实际应用程序所需的位置”并不是一种可靠的检查解决方案。 - Chris
4
@Chris:这取决于你是否真的关心问题所在。我同意,如果(发生故障后)您连接到其他地方,您可以获得更多的诊断信息。但最重要的信息肯定是“我能否使用我正在尝试使用的资源?” - Jon Skeet
2
@Pacerier:有很多不同的问题可能会出现,而诊断问题所在是一件棘手的事情。如果你什么都没做,但是你的ISP到世界其他地方的管道已经断了呢?那么你可能仍然拥有一个完全有效的路由器连接等 - 甚至你可能能够访问你的ISP域名 - 但无法访问其他网站。我只是想说,“我的互联网正常吗?”这个问题在精确的术语中并没有意义。你提出的测试应该是什么? - Jon Skeet
1
@Pacerier:所以你可以尝试访问一些通常正常的网站。你还需要检查DNS解析是否正常,确保facebook.com能够被解析。此外,有可能Facebook对大部分用户不可用(例如某个国家的流量都指向一个出现问题的数据中心),但并不是完全宕机的情况。 - Jon Skeet
显示剩余7条评论

28

你提供的基本代码再加上调用 connect 应该就足够了。所以,可能只是 Google 不可用,但需要联系的其他网站却可用,但这种情况有多大可能呢?此外,该代码应该仅在实际无法访问外部资源时执行(在 catch 块中尝试查明失败的原因),因此我认为,如果你感兴趣的外部资源 Google 都不可用,那么很可能是网络连接问题。

private static boolean netIsAvailable() {
    try {
        final URL url = new URL("http://www.google.com");
        final URLConnection conn = url.openConnection();
        conn.connect();
        conn.getInputStream().close();
        return true;
    } catch (MalformedURLException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        return false;
    }
}

这个可以工作,但需要一段时间才能返回“false”。有更快的解决方案吗?当我尝试ping它时,“Cmd”立即告诉我找不到主机。 - BullyWiiPlaza

18

人们建议使用INetAddress.isReachable。问题在于,一些网站会配置其防火墙以阻止ICMP Ping消息。因此,“ping”可能会失败,即使Web服务是可访问的。

当然,反过来也是如此。虽然Web服务器已关闭,但主机可能仍会响应ping。

当然,由于本地防火墙限制,计算机可能无法直接连接到某些(或所有)Web服务器。

根本问题在于,“能否连接到互联网”是一个含糊不清的问题,这种情况很难进行测试,而不需要:

  1. 用户的计算机和“本地”网络环境的信息,以及
  2. 应用程序需要访问什么信息的信息。

因此,通常最简单的解决方案是让应用程序尝试访问它需要访问的任何内容,并借助人类智慧进行诊断。


良好的定义,没有模糊不清的地方。问题只是“是否有互联网”,没有更多的内容。 - Chris
5
那就是我的观点。问题“有没有互联网”定义不清楚。请阅读上面的文本以获取旨在说明此点的示例。 - Stephen C
1
@Chris:“互联网”这个词并没有明确定义。能够访问Google并不意味着你一定能够访问其他任何地方,例如:想象一下如果DNS服务器宕机了,但是你在主机文件中恰好有一个DNS条目。 - Jon Skeet
无法访问Google并不意味着您不能访问用户实际想要去的地方。 - Stephen C
@Stephen C:好的,现在我明白了。也许我需要尝试另一种方法来满足我的需求。感谢您的评论。 - Chris

9
这段代码应该能可靠地完成任务。
需要注意的是,当使用 try-with-resources 语句时,我们不需要关闭资源。
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class InternetAvailabilityChecker
{
    public static boolean isInternetAvailable() throws IOException
    {
        return isHostAvailable("google.com") || isHostAvailable("amazon.com")
                || isHostAvailable("facebook.com")|| isHostAvailable("apple.com");
    }

    private static boolean isHostAvailable(String hostName) throws IOException
    {
        try(Socket socket = new Socket())
        {
            int port = 80;
            InetSocketAddress socketAddress = new InetSocketAddress(hostName, port);
            socket.connect(socketAddress, 3000);

            return true;
        }
        catch(UnknownHostException unknownHost)
        {
            return false;
        }
    }
}

8
如果您使用的是Java 6,可以使用NetworkInterface来检查可用的网络接口。例如,可以使用以下代码:
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
  NetworkInterface interf = interfaces.nextElement();
  if (interf.isUp() && !interf.isLoopback())
    return true;
}

我自己还没有尝试过。


3
这仅仅检查接口是否启用,它并不检查互联网连接。 - siamii
然而,网络接口处于启动状态是互联网连接的先决条件。我认为这是更强大的解决方案的第一步。它允许您至少查看是否有活动的网络接口,而不需要发送任何网络流量。 - adamfisk
这不是OP所要求的。 - user207421
原帖作者并没有理解“互联网是否正常”的问题是不明确的,因为互联网包含了很多东西,其中任何一个出现故障都会导致各种类型的失败。这是其中之一,并且对于原帖作者或其他查看此问题的人来说,这是潜在有用的信息。原帖作者拒绝简单地连接到所需资源。如果无法连接,则这是回答不明确的原始问题的众多步骤之一。 - Jeff Learman

8

这段代码:

"127.0.0.1".equals(InetAddress.getLocalHost().getHostAddress().toString());

返回结果:如果离线,则返回true,否则返回false(我不确定这对所有计算机都适用)。

这种方法比其他方法快得多。


编辑:我发现只有在“翻转开关”(笔记本电脑上)或其他系统定义选项关闭互联网连接时,它才能正常工作。即,系统本身知道不要寻找任何IP地址。


无法在“127.0.0.1”上工作,但可以对其他可达的IP地址显示回复。 - Harshit
对我来说很好用,我喜欢它并一直在使用。这是一种预检查。在检查互联网连接之前,您可以调用它来确保网络接口已连接。 - kinORnirvana
这完全是胡说八道:InetAddress.getLocalHost().getHostAddress()会给你在你的网络中的本地IP地址。所以例如像10.0.0.1或者192.168.0.1这样的东西。结果与你的在线/离线状态无关。 - Jörg

6

InetAddress.isReachable有时会在存在Internet连接时返回false。

Java中检查互联网可用性的替代方法是: 此函数执行实际的ICMP ECHO ping。

public static boolean isReachableByPing(String host) {
     try{
                String cmd = "";
                if(System.getProperty("os.name").startsWith("Windows")) {   
                        // For Windows
                        cmd = "ping -n 1 " + host;
                } else {
                        // For Linux and OSX
                        cmd = "ping -c 1 " + host;
                }

                Process myProcess = Runtime.getRuntime().exec(cmd);
                myProcess.waitFor();

                if(myProcess.exitValue() == 0) {

                        return true;
                } else {

                        return false;
                }

        } catch( Exception e ) {

                e.printStackTrace();
                return false;
        }
}

4

使用NetworkInterface等待网络的代码对我来说是有效的,直到我从固定网络地址切换到DHCP。稍加改进后,它也可以与DHCP一起工作:

Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
    NetworkInterface interf = interfaces.nextElement();
    if (interf.isUp() && !interf.isLoopback()) {
    List<InterfaceAddress> adrs = interf.getInterfaceAddresses();
    for (Iterator<InterfaceAddress> iter = adrs.iterator(); iter.hasNext();) {
        InterfaceAddress adr = iter.next();
        InetAddress inadr = adr.getAddress();
        if (inadr instanceof Inet4Address) return true;
            }
    }
}

这适用于在openSuse 13.1上使用Java 7进行IPv4网络连接。原始代码的问题是,尽管从挂起状态恢复后接口已经启动,但IPv4网络地址尚未分配。等待地址分配后,程序可以连接服务器。但我不知道在IPv6的情况下该怎么办。


4
URL url=new URL("http://[any domain]");
URLConnection con=url.openConnection();

/*now errors WILL arise here, i hav tried myself and it always shows "connected" so we'll open an InputStream on the connection, this way we know for sure that we're connected to d internet */

/* Get input stream */
con.getInputStream();

将上述语句放入try catch块中,如果捕获到异常,则表示没有建立互联网连接。 :-)

4

我通常将它分为三个步骤。

  1. 首先,我会尝试将域名解析为IP地址。
  2. 然后,我会尝试通过TCP连接(端口80和/或443)并优雅地关闭连接。
  3. 最后,我会发出HTTP请求并检查是否返回200响应。

如果在任何一个步骤失败,我会向用户提供相应的错误消息。


2
我认为这可能是一个不错的答案,但你能否详细说明一下,因为现在它还不够好。 - Pacerier

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