Java 我可以在Android中为DefaultHttpClient设置getaddrinfo超时吗?

Java 我可以在Android中为DefaultHttpClient设置getaddrinfo超时吗?,java,android,http,networking,connectivity,Java,Android,Http,Networking,Connectivity,在Android应用程序中,我试图测试用户是否有正常的互联网连接。如果你感兴趣,在前面的问题中有一些背景知识 代码基本上如下所示: try { HttpParams myParams = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(myParams, 10000); HttpConnectionParams.setSoTimeout(myParams, 10000); http

在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无法访问互联网,则我在例外情况下遇到的错误是:

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

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


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

我做了一点家庭作业,似乎你无法调整DNS查找超时。因此,我认为更好的方法是显式DNS查找,这样我就可以控制它(并希望缓存结果以加快下一次尝试)。这让我想到了一个简单的问题:

InetAddress addr = InetAddress.getByName(hostname);
但这也有45秒的超时时间。其他人也提到了这一点。最后,我偶然发现了一个简单的解决方案,只需在单独的线程中启动查找并管理自己的超时。这很好地说明了这一点

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;
    }
}

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

太棒了,谢谢。令人惊讶的是,这是关于这个非常重要的用例的唯一帖子。例如,有人在热点上使用我的应用程序(可能过载、速度慢或根本没有连接到互联网)。导致我们出现问题的情况我们称之为“酒店WiFi问题CEO”。我们的首席执行官将在一家酒店,他的手机将连接到酒店的wifi。但是,他会忘记运行网络浏览器,而实际登录酒店的wifi以获得完整的网络访问。他将被限制在酒店网络的围墙花园内,当他运行我们的应用程序时,它无法到达我们的服务器。我们进行这项测试是为了提醒我们的CEO(和我们的用户)当他们没有真正的工作互联网接入时。我将使用您的方法与exec(ping)相结合,以便在连接到wifi而不是互联网时避免长时间的dns错误延迟。对于这些阅读,请记住dns是缓存的,因此在第一次dns检查之后,您需要ping来检查internet(ICMP)连接。无法找到其他方法来避免长时间的硬编码(20sec)dns超时。请注意,InetAddr.isReachable()方法执行需要根访问权限的低级ICMP调用。执行官(ping)没有。(8.8.8.8)@DominicCresano并非所有服务器都接受ICMP请求though@cbreezier我给出的示例(8.8.8.8)是一个启用ICMP的Google DNS服务器。