2014-11-28 3 views
3

Android의 DefaultHttpClient에 시간 초과 문제가 있습니다. 나는 다음과 같은 코드 조각으로 시간 제한을 설정하기 위해 노력하고있어 : Android가 DefaultHttpClient 시간 초과 매개 변수를 무시합니다.

HttpClient client = new DefaultHttpClient(); 
HttpParams httpParameters = client.getParams(); 
HttpConnectionParams.setConnectionTimeout(httpParameters, 4000); 
HttpConnectionParams.setSoTimeout(httpParameters, 4000); 

그러나 장치가 인터넷에 연결하지 않고 네트워크에 연결되어있는 경우, 타임 아웃이 발사되지 않습니다 및 HTTP 요청의 실행이 결코 모든 시간 초과가 발생하지 않습니다

예외. 다음 줄에, 나는 HttpRequest에에 시간 제한을 설정할 수도 시도했다

HttpResponse httpResponse = client.execute(request); 

: 나는 다음과 같이 HTTP 요청을 실행하고있어

HttpRequestBase request = ... 
request.setParams(httpParameters); 

안드로이드는 때 시간 제한 설정을 무시하고 것 같습니다 인터넷 연결이없는 네트워크에서 http 요청을 실행하면 약 20 초 후에 모든 요청이 실패하고 시간 초과 설정은 실패합니다.

또한 모든 인터넷 연결을 닫고 병렬 스레드로 시간 초과 후 http 요청을 중단하려고했습니다. 어떤

HttpClient client = new DefaultHttpClient(); 
HttpParams httpParameters = client.getParams(); 

HttpRequestBase request = ... 
request.setParams(httpParameters); 

HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutReal); 
HttpConnectionParams.setSoTimeout(httpParameters, timeoutReal); 

request.setParams(httpParameters); 
((DefaultHttpClient) client).setParams(httpParameters); 

Thread t = new Thread(){ 
    public void run() 
    { 
     try 
     { 
      Thread.sleep(4000); 
      request.abort(); 
      client.getConnectionManager().closeExpiredConnections(); 
      client.getConnectionManager().closeIdleConnections(4000,TimeUnit.MILLISECONDS); 
      client.getConnectionManager().shutdown(); 
      Log.i("TEST SHUTDOWN","SHUT DOWN ALL CONNECTIONS"); 
       } 
      catch (InterruptedException e) 
      { 
      } 
     } 
    }; 

try 
{ 
    t.start(); 
    HttpResponse httpResponse = client.execute(request); 
} 
catch (Exception e) 
{ 
    Log.i("TEST SHUTDOWN","EXCEPTION "+e); 
} 
finally 
{ 
    t.interrupt(); 
} 

하지만 요청이 중단되고 연결 관리자가 종료 로그에서 볼 경우에도 요청의 실행이 중단 된/중단하지 않고 : 나는 다음과 같은 코드 조각을 사용했습니다 타임 아웃 세트로 예외가 발생합니다. 요청은 항상 20 초 후에 끝납니다.

왜 그런가?

+0

여기 접근 방법을 시도해 보셨나요? http://stackoverflow.com/questions/11638634/android-how-to-set-a-http-connection-timeout-and-react-to-it –

+0

예, 시도했습니다. . 그러나 문제는 항상 동일합니다. –

+0

이상한, 이걸 재현 할 수 없습니다 ... – matiash

답변

7

아마도 DNS 조회가 시간 초과된다는 것입니다. HTTP 클라이언트가 연결을 시도 할 때 URL의 호스트 이름을 IP 주소로 변환하려고합니다. 이렇게하면 시간 초과 설정을 고려하지 않습니다 (시간 초과 값은 소켓 연결을 실제로 만들려고 할 때만 사용됩니다). 인터넷 연결 상태가 좋지 않은 경우 시간이 초과 될 때까지 DNS 조회가 중단됩니다. 그렇게되면 UnknownHostException으로 즉시 HTTP 요청이 실패합니다.

아쉽게도 DNS 시간 초과를 제어 할 수 없으므로 문제를 해결할 수있는 유일한 방법은 먼저 DNS 확인이 작동하는지 확인하는 것입니다. 이 작업은 별도의 스레드에서 수행해야하며, 몇 초 내에 성공적인 호스트 확인을 얻지 못하면 인터넷 연결이 안정적이지 않고 HTTP 요청을 시도하지 않아도된다는 것을 알고 있습니다.그래서 오타되거나 누락 된 세미콜론을 용서하십시오, 그것을 시도하지 않고

HttpClient client = new DefaultHttpClient(); 
HttpParams httpParameters = client.getParams(); 

HttpRequestBase request = ... 
request.setParams(httpParameters); 

HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutReal); 
HttpConnectionParams.setSoTimeout(httpParameters, timeoutReal); 

request.setParams(httpParameters); 
((DefaultHttpClient) client).setParams(httpParameters); 

// The thread that is waiting to execute the HTTP request 
final Thread waitingThread = Thread.currentThread(); 

Thread t = new Thread() { 
    boolean running = true; 
    public void run() { 
     try { 
      // Try to resolve the host name 
      InetAddress addr = InetAddress.getByName (hostname); 
      // Successful resolution, notify the waiting thread 
      if (running) { 
       // Signal the waiting thread that it can do the HTTP request now 
       waitingThread.interrupt(); 
      } 
     } catch (Exception e) { 
      // Some problem, just ignore it 
     } 
    } 
}; 

try { 
    // Start name resolution 
    t.start(); 
    // Sleep for as long as we are willing to wait for the DNS resolution 
    Thread.sleep(4000); 
    // If we slept the entire time without getting interrupted, the DNS resolution took too long 
    // so assume we have no connectivity. 
    t.running = false; // We don't want to be interrupted anymore 
    // Don't even bother trying the HTTP request now, we've used up all the time we have 
} catch (InterruptedException ie) { 
    // We got interrupted, so the DNS resolution must have been successful. Do the HTTP request now 
    HttpResponse httpResponse = client.execute(request); 
} 

이 코드를 쓰고 있어요 :

그래서 당신은 이런 식으로 뭔가를 시도 할 수 있습니다. 아이디어를 얻어야합니다.

+1

정확할 수 있습니다. 이 설명과 일치하는 도달 불가능한 IP 주소 (예 :'10.255.255.1')를 사용할 때 문제가 발생하지 않습니다. – matiash

+0

@matiash 문제를 재현 할 수 없다고 말한 것 같습니다. –

+1

정확하게 (연결 상태가 좋지 않은 상태에서) "연결할 수없는"주소로 IP를 사용하여 연결 시간 초과를 유발했기 때문에 (올바른 기간이 있음) 정확합니다. 나는 DNS 결의안이 관련 될 수 있다고 생각하지 못했습니다! :) – matiash

1

DefaultHttpClient 대신 AndroidHttpClient를 사용해 볼 수 있습니다. Android 용 특정 설정이 있습니다. 다음 줄

HttpParams httpParameters = new BasicHttpParams(); 

이 정답입니다 만하면 나도 몰라과

HttpParams httpParameters = client.getParams(); 

을이 도움이되기를 바랍니다 :

또는, 다음 줄을 대체하기 위해 시도 할 수 있습니다.

+1

AndroidHttpClient를 사용하려고했지만 문제가 동일하게 남아 있으며 시간 초과 문제가 사라지지 않습니다 ... 답장을 보내 주셔서 감사합니다! –

0

질문의 20 초 부분 rfc2616은 5 리디렉션 시간 4000 밀리 = 20 초를 지정합니다. 해결책은 네트워크 액세스를 시도하기 전에 네트워크 연결을 확인하는 것입니다.

// check for network connection 
     ConnectivityManager connMgr = (ConnectivityManager) context 
       .getSystemService(Context.CONNECTIVITY_SERVICE); 
     if (connMgr == null) { 
      return false; // I get a null here when there is no connection on my lg f6. 
     } 

     // check ok to process 
     NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); 
     if (networkInfo == null || !networkInfo.isConnected()) { 
      return false; 
     } 

     return true; 
+2

네트워크 연결이 불량하고 장치가 연결되어있어 응답 한 솔루션이 작동하지 않는 경우에도 문제가 발생합니다. –

0

음, 비슷한 문제가있었습니다. 이것이 내가 해결 한 일입니다. 내가 설정을 수동으로 설정하지 않는, 그런

HttpParams params = new BasicHttpParams(); 

:

첫째, 나는 HttpParams의 인스턴스를 만듭니다. 대신 나는 HttpConnectionParams 클래스를 사용합니다. 예를 들면 : 나는 HTML 클라이언트의 인스턴스를 할 때 다음

HttpConnectionParams.setStaleCheckingEnabled(params, false); 
HttpConnectionParams.setConnectionTimeout(params, httpTimeout * 1000); 
HttpConnectionParams.setSoTimeout(params, httpTimeout * 1000); 

, 내가 만든 PARAMS을 통과 :

HttpClient client = new DefaultHttpClient(params); 

나는 또한 클라이언트 연결 관리자를 사용합니다, 그래서, 나는 첫 번째 매개 변수로 전달 위의 전화.

그래서 트릭은 이미 설정된 매개 변수를 전달하고 나중에 매개 변수를 지정하지 않고 HttpClient를 만드는 것입니다.

희망이 당신을 위해 작동합니다.

편집 : 리디렉션을 차단하려고 시도 했습니까? HttpClientParams.setRedirecting(params, setRedirecting);

+1

그 해결책도 시도했지만 작동하지 않았습니다 –

+0

그리고 연결 관리자에서 위의 방법을 사용해 보았습니까? – pedrop

+0

예 ... Thread Safe 연결 관리자로 시도했지만 작동하지 않습니다. –

관련 문제