Http connection timeout on Android not working

2019-01-05 10:26发布

I'm writing an application that connects to a webservice and I don't want it to wait too long if it can't get a connection. I therefore set the connectionTimeout of the httpparams. But it doesn't seem to have any effect whatsoever.

To test I turn of my WLAN temporarily. The application tries to connect for quite some time (way more than the 3 seconds I want) and then throws an UnknownHostException.

Here is my code:

try{
    HttpClient httpclient = new DefaultHttpClient();
    HttpParams params = httpclient.getParams();
    HttpConnectionParams.setConnectionTimeout(params, 3000);
    HttpConnectionParams.setSoTimeout(params, 3000);

    httppost = new HttpPost(URL);
    StringEntity se = new StringEntity(envelope,HTTP.UTF_8);
    httppost.setEntity(se);
    //Code stops here until UnknownHostException is thrown.
    BasicHttpResponse httpResponse = (BasicHttpResponse) httpclient.execute(httppost);

    HttpEntity entity = httpResponse.getEntity();
    return entity;

}catch (Exception e){
    e.printStackTrace();
}

Anyone have any ideas what I missed?

5条回答
▲ chillily
2楼-- · 2019-01-05 10:42
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT)
查看更多
萌系小妹纸
3楼-- · 2019-01-05 10:58

With the marked solution I am still getting a UnknownHostException after 30+ seconds. In this case the device is connected to a wifi router but there is no internet access.

The approach taken was to kick off an AsyncTask that will just attempt to resolve the hostname. The blocking call checks every 250 ms to see if it succeeded, and after 4 seconds it will cancel the task and return.

This is what I did to solve it:

private boolean dnsOkay = false;
private static final int DNS_SLEEP_WAIT = 250;
private synchronized boolean resolveDns(){

    RemoteDnsCheck check = new RemoteDnsCheck();
    check.execute();
    try {
        int timeSlept = 0;
        while(!dnsOkay && timeSlept<4000){
            //Log.d("RemoteDnsCheck", "sleeping");
            Thread.sleep(DNS_SLEEP_WAIT);
            timeSlept+=DNS_SLEEP_WAIT;
            //Log.d("RemoteDnsCheck", "slept");
        }
    } catch (InterruptedException e) {

    }

    if(!dnsOkay){
        Log.d("resolveDns", "cancelling");
        check.cancel(true);
        Log.d("resolveDns", "cancelled");
    }
    return dnsOkay;
}

private class RemoteDnsCheck extends AsyncTask<Void, Void, Void>{

    @Override
    protected Void doInBackground(Void... params) {
        try {
            Log.d("RemoteDnsCheck", "starting");
            dnsOkay = false;
            InetAddress addr = InetAddress.getByName(baseServiceURL);
            if(addr!=null){
                Log.d("RemoteDnsCheck", "got addr");
                dnsOkay = true;
            }
        } catch (UnknownHostException e) {
            Log.d("RemoteDnsCheck", "UnknownHostException");
        }
        return null;
    }

}

Then, any time I want to do a web call, this is called at the beginning of the function:

    if(!resolveDns()){
        return null;
    }
查看更多
Luminary・发光体
4楼-- · 2019-01-05 11:00

This method works for me :

AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport( endpoint, 3000) ;
查看更多
我只想做你的唯一
5楼-- · 2019-01-05 11:02

See: https://stackoverflow.com/a/20031077/2609238

The problem might be in the Apache HTTP Client. See HTTPCLIENT-1098. Fixed in 4.1.2.

The timeout exception tries to reverse DNS the IP, for logging purposes. This takes an additional time until the exception is actually fired.

查看更多
等我变得足够好
6楼-- · 2019-01-05 11:04

Try to do it this way:

HttpPost httpPost = new HttpPost(url);
StringEntity se = new StringEntity(envelope,HTTP.UTF_8);
httpPost.setEntity(se);

HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established.
int timeoutConnection = 3000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT) 
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 3000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
BasicHttpResponse httpResponse = (BasicHttpResponse)  httpClient.execute(httpPost);

HttpEntity entity = httpResponse.getEntity();
return entity;

You then can catch a possible ConnectTimeoutException.

查看更多
登录 后发表回答