我正在努力解决以下问题:
我的应用程序使用HttpClient向HTTP服务器发出请求序列。我使用HttpPut将数据发送到服务器。
第一个请求运行良好且快速,第二个请求挂起40秒,然后我捕获到Connection超时异常。我正在尝试重用HttpClient并通过同一实例发送第二个请求。如果我与新的ConnectionManager一起创建新的HttpClient,则一切正常。

为什么会这样呢?以及如何解决它,并且不要每次都创建新的HttpClient?

提前致谢。

这是我的代码:(如果我在doPut中注释readClient = newHttpClient(readClient),则会出现问题。

public class WebTest
{
private HttpClient readClient;
private SchemeRegistry httpreg;
private HttpParams params;

private URI url; //http://my_site.net/data/

protected HttpClient newHttpClient(HttpClient oldClient)
{
    if(oldClient != null)
        oldClient.getConnectionManager().shutdown();

    ClientConnectionManager cm = new SingleClientConnManager(params, httpreg);
    return new DefaultHttpClient(cm, params);
}

protected String doPut(String data)
{
    //****************************
    //Every time we need to send data, we do new connection
    //with new ConnectionManager and close old one
    readClient = newHttpClient(readClient);

    //*****************************


    String responseS = null;
    HttpPut put = new HttpPut(url);
    try
    {
        HttpEntity entity = new StringEntity(data, "UTF-8");
        put.setEntity(entity);
        put.setHeader("Content-Type", "application/json; charset=utf-8");
        put.setHeader("Accept", "application/json");
        put.setHeader("User-Agent", "Apache-HttpClient/WebTest");

        responseS = readClient.execute(put, responseHandler);
    }
    catch(IOException exc)
    {
        //error handling here
    }
    return responseS;
}

public WebTest()
{
    httpreg = new SchemeRegistry();
    Scheme sch = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
    httpreg.register(sch);

    params = new BasicHttpParams();
    ConnPerRoute perRoute = new ConnPerRouteBean(10);
    ConnManagerParams.setMaxConnectionsPerRoute(params, perRoute);
    ConnManagerParams.setMaxTotalConnections(params, 50);
    ConnManagerParams.setTimeout(params, 15000);
    int timeoutConnection = 15000;
    HttpConnectionParams.setConnectionTimeout(params, timeoutConnection);
    // Set the default socket timeout (SO_TIMEOUT)
    // in milliseconds which is the timeout for waiting for data.
    int timeoutSocket = 40000;
    HttpConnectionParams.setSoTimeout(params, timeoutSocket);
}

private ResponseHandler<String> responseHandler = new ResponseHandler<String>()
{
    @Override
    public String handleResponse(HttpResponse response)
            throws ClientProtocolException, IOException
    {
        StatusLine statusLine = response.getStatusLine();
        if (statusLine.getStatusCode() >= 300)
        {
            throw new HttpResponseException(statusLine.getStatusCode(),
                    statusLine.getReasonPhrase());
        }

        HttpEntity entity = response.getEntity();
        if(entity == null)
            return null;

        InputStream instream = entity.getContent();
        return this.toString(entity, instream, "UTF-8");
    }

    public String toString(
            final HttpEntity entity,
            final InputStream instream,
            final String defaultCharset) throws IOException, ParseException
    {
        if (entity == null)
        {
            throw new IllegalArgumentException("HTTP entity may not be null");
        }

        if (instream == null)
        {
            return null;
        }
        if (entity.getContentLength() > Integer.MAX_VALUE)
        {
            throw new IllegalArgumentException("HTTP entity too large to be buffered in memory");
        }
        int i = (int)entity.getContentLength();
        if (i < 0)
        {
            i = 4096;
        }
        String charset = EntityUtils.getContentCharSet(entity);
        if (charset == null)
        {
            charset = defaultCharset;
        }
        if (charset == null)
        {
            charset = HTTP.DEFAULT_CONTENT_CHARSET;
        }

        Reader reader = new InputStreamReader(instream, charset);

        StringBuilder buffer=new StringBuilder(i);
        try
        {
            char[] tmp = new char[1024];
            int l;
            while((l = reader.read(tmp)) != -1)
            {
                buffer.append(tmp, 0, l);
            }
        } finally
        {
            reader.close();
        }

        return buffer.toString();
    }
};

}

最佳答案

听起来很奇怪,但是我遇到了完全相同的问题。我正在开发的应用程序连续发出多个请求,以下载一堆缩略图以显示在ListView中,在第二个请求之后,它将挂起,就好像HttpClient代码中的死锁一样。

我发现的奇怪修复是使用AndroidHttpClient而不是DefaultHttpClient。一旦做到这一点,在尝试这条路线之前,我尝试了很多东西,它开始工作正常。完成请求后,请记住要调用client.close()。

文档中将AndroidHttpClient描述为DefaultHttpClient,其中包含“Android的合理默认设置和注册方案”。由于此功能是在api级别8(Android 2.2)中引入的,因此我挖了源代码来复制这些“默认设置”,以便可以比该api级别更远地使用它。这是我的代码,用于使用静态方法复制默认值和帮助程序类,以安全地关闭它

public class HttpClientProvider {

    // Default connection and socket timeout of 60 seconds. Tweak to taste.
    private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000;

    public static DefaultHttpClient newInstance(String userAgent)
    {
        HttpParams params = new BasicHttpParams();

        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
        HttpProtocolParams.setUseExpectContinue(params, true);

        HttpConnectionParams.setStaleCheckingEnabled(params, false);
        HttpConnectionParams.setConnectionTimeout(params, SOCKET_OPERATION_TIMEOUT);
        HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT);
        HttpConnectionParams.setSocketBufferSize(params, 8192);

        SchemeRegistry schReg = new SchemeRegistry();
        schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
        ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);

        DefaultHttpClient client = new DefaultHttpClient(conMgr, params);

        return client;
    }

}

还有另一个类
public static void safeClose(HttpClient client)
{
    if(client != null && client.getConnectionManager() != null)
    {
        client.getConnectionManager().shutdown();
    }
}

07-24 09:47
查看更多