7

在一个 Android 应用程序中,我正在尝试测试用户是否具有有效的 Internet 连接。如果您有兴趣,可以参考上一个问题Detecting limited network connectivity in Android? 中的一些背景知识?

代码基本上是这样的:

try {
    HttpParams myParams = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(myParams, 10000);
    HttpConnectionParams.setSoTimeout(myParams, 10000);

    httpClient = new DefaultHttpClient(myParams);

    request = new HttpHead(url);
    response = httpClient.execute(request);
    statusCode = response.getStatusLine().getStatusCode();

    if (statusCode != 200)
    {       
        return false;
    }
    return true;

} catch(Exception e) {
    return false;
}

我可以使用 HttpConnectionParams 控制连接和套接字的超时。但是,如果我的设备已连接到 Wifi,但 wifi 无法访问 Internet,我在异常中遇到的错误是:

libcore.io.GaiException:getaddrinfo 失败:EAI_NODATA(没有与主机名关联的地址)

无法解析主机“www.example.com”:没有与主机名关联的地址

看起来它在 DNS 查找时超时。我可以控制 DNS 查找的超时时间吗?httpClient.execute 需要大约 45 秒才能失败,但上述异常除外。我希望它早点放弃。

4

1 回答 1

12

我做了一些功课,似乎您无法调整 DNS 查找超时。因此,我认为更好的方法是进行显式 DNS 查找,以便我可以控制它(并希望缓存结果以加快下一次尝试)。所以这让我很简单:

InetAddress addr = InetAddress.getByName(hostname);

但这也有 45 秒的超时。其他人提到无法控制 getByName() 的超时。最后,我偶然发现了一个简单的解决方案,只需在单独的线程中启动查找并管理您自己的超时。这篇博文很好地说明了这一点。

private static boolean testDNS(String hostname) {
  try
  {
    DNSResolver dnsRes = new DNSResolver(hostname);
    Thread t = new Thread(dnsRes);
    t.start();
    t.join(1000);
    InetAddress inetAddr = dnsRes.get();            
    return inetAddr != null;
  }
  catch(Exception e)
  { 
    return false;
  }
}

private static class DNSResolver implements Runnable {
    private String domain;
    private InetAddress inetAddr;

    public DNSResolver(String domain) {
        this.domain = domain;
    }

    public void run() {
        try {
            InetAddress addr = InetAddress.getByName(domain);
            set(addr);
        } catch (UnknownHostException e) {                
        }
    }

    public synchronized void set(InetAddress inetAddr) {
        this.inetAddr = inetAddr;
    }
    public synchronized InetAddress get() {
        return inetAddr;
    }
}

使用它我可以首先测试设备是否可以解析主机名,然后是否成功进行完整的连接测试。

于 2013-08-15T03:01:32.410 回答