2013-08-13 1 views
3

В приложении для Android я пытаюсь проверить, работает ли у пользователя рабочее интернет-соединение. Если вас интересует, есть некоторый фон в предыдущем вопросе Detecting limited network connectivity in Android?Могу ли я установить тайм-аут getaddrinfo в Android для DefaultHttpClient?

Код, в основном, как:

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. Но, если мое устройство подключено к Wi-Fi, но Wi-Fi не имеет доступа к Интернету, то ошибка Я получаю за исключением не является:

libcore.io.GaiException: getaddrinfo не удалось: EAI_NODATA (без адреса связано с именем хоста)

Невозможно решить множество «www.example.com»: Нет адрес, связанный с именем хоста

, который выглядит, как он таймаут на DNS-поиска. Могу ли я контролировать тайм-аут DNS-поиска? httpClient.execute занимает около 45 секунд, чтобы сбой с исключением, указанным выше. Я бы хотел, чтобы он сдался раньше.

ответ

7

Я сделал небольшую домашнюю работу, и, похоже, вы не можете настроить тайм-аут поиска DNS. Итак, я решил, что лучший подход будет заключаться в явном поиске DNS, чтобы я мог контролировать его (и, надеюсь, результат кэшируется, чтобы ускорить следующую попытку). Так что это привело меня к простому:

InetAddress addr = InetAddress.getByName(hostname); 

, но у этого также был тайм-аут 45 секунд. Другие упоминали, что было no control of the timeout for getByName(). Наконец, я наткнулся на простое решение, просто запустил поиск в отдельном потоке и управлял собственным таймаутом. This blog post показывает это довольно хорошо.

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

Используя это, я могу сначала проверить, может ли устройство разрешить имя хоста, а затем успешно ли оно пройти тест на полную совместимость.

+0

Удивительный, спасибо. Удивлен, что это единственное сообщение об этом очень важном случае использования. Например, кто-то использует мое приложение поверх горячих точек (которые могут быть перегружены, медленны или просто не подключены к Интернету). –

+0

Ситуация, вызвавшая наши проблемы, мы назвали «CEO по проблеме WiFi в отеле». Наш генеральный директор будет в отеле, и его телефон будет подключен к Wi-Fi отеля. Но он забыл запустить веб-браузер и фактически войти в Wi-Fi отеля, чтобы получить полный доступ к сети. Он будет ограничен огороженным садом сети отеля, и когда он запустит наше приложение, он не сможет дойти до наших серверов. Мы поставили этот тест, чтобы напомнить нашему генеральному директору (и нашим пользователям), когда у них действительно нет доступа к Интернету. –

+0

Я использую ваш подход в сочетании с exec (ping), чтобы обойти длинные задержки DNS-сообщений при подключении к Wi-Fi, но не к интернету. Для тех, кто читает, помните, что dns кэшируется, поэтому вам нужно выполнить ping, чтобы проверить подключение к Интернету (ICMP) после первой проверки DNS. Не удалось найти другого способа избежать длительного времени ожидания жесткого кодирования (20 секунд). Обратите внимание, что метод InetAddr.isReachable() выполняет низкоуровневый ICMP-вызов, требующий доступа root. exec (ping) нет. (8.8.8.8) –