android httpclient挂起对服务器的第二个请求(连接超时)

我正在努力解决以下问题:我的应用程序使用HttpClient向http服务器发出一系列请求。 我使用HttpPut将数据发送到服务器。 第一个请求顺利,快速,第二个请求挂起40秒,然后我赶上连接超时exception。 我试图重用我的HttpClient并通过同一个实例发送第二个请求。 如果我与新的ConnectionManager一起创build新的HttpClient,那么一切正常。

为什么发生这种情况? 以及如何解决这个问题,而不是每次创build新的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(); } }; 

}

Solutions Collecting From Web of "android httpclient挂起对服务器的第二个请求(连接超时)"

听起来很奇怪,但我有完全相同的问题。 我正在做的应用程序正在做几个连续的请求,下载一个缩略图图像显示在一个ListView中,第二个之后,它会挂起,就像在HttpClient代码中有一个死锁。

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

AndroidHttpClient在文档中用“合理的默认设置和Android注册scheme”描述为DefaultHttpClient。 由于这是在api level 8(Android 2.2)中引入的,我挖掘了源代码以复制这些“默认设置”,以便我可以使用它比api级别更远的地方。 这里是我的代码复制默认和一个帮助类与静态方法安全地closures它

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

而在另一class…

 public static void safeClose(HttpClient client) { if(client != null && client.getConnectionManager() != null) { client.getConnectionManager().shutdown(); } } 

听起来就像你在完成处理响应之后不会消耗实体。 确保你把下面的代码放在finally块中:

 if (httpEntity != null) { try { httpEntity.consumeContent(); } catch (IOException e) { Log.e(TAG, "", e); } } 

我build议你阅读HttpClient教程 。

在循环中执行多个请求时,我遇到了同样的麻烦。

你可以通过阅读所有response.getEntity()来解决它。

我想我会详细说明其他答案。 我也遇到过这个问题。 问题是因为我没有使用内容。

看来,如果你不这样做,连接将保持,并且你不能发送一个新的请求与这个相同的连接。 对我来说,这是一个特别困难的错误,因为我使用的是Android提供的BasicResponseHandler 。 代码看起来像这样…

 public String handleResponse(final HttpResponse response) throws HttpResponseException, IOException { StatusLine statusLine = response.getStatusLine(); if (statusLine.getStatusCode() >= 300) { throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); } HttpEntity entity = response.getEntity(); return entity == null ? null : EntityUtils.toString(entity); } 

所以如果有一个300以上的状态行,那么我不会消耗内容。 我的情况有内容。 我这样做了我自己的class级

 public class StringHandler implements ResponseHandler<String>{ @Override public BufferedInputStream handleResponse(HttpResponse response) throws IOException { public String handleResponse(final HttpResponse response) throws HttpResponseException, IOException { StatusLine statusLine = response.getStatusLine(); HttpEntity entity = response.getEntity(); if (statusLine.getStatusCode() >= 300) { if (entity != null) { entity.consumeContent(); } throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); } return entity == null ? null : EntityUtils.toString(entity); } } } 

所以基本上无论如何消耗内容!

我有这个相同的问题。 我正在消耗所有的内容。

我发现如果我在发出请求后做垃圾收集,一切都可以正常工作,而不必closures并创build一个新的AndroidHttpClient:

的System.gc();

问题解决scheme(我有相同的)就足够了:

 EntityUtils.consume(response.getEntity()); 

在消耗内执行空值检查

由于许多这些答案是旧的,并依赖于现在depricated consumeContent()方法,我想我会回答替代Timeout waiting for connection from pool

  HttpEntity someEntity = response.getEntity(); InputStream stream = someEntity.getContent(); BufferedReader rd = new BufferedReader(new InputStreamReader(stream)); StringBuffer result = new StringBuffer(); String line = ""; while ((line = rd.readLine()) != null) { result.append(line); } // On certain android OS levels / certain hardware, this is not enough. stream.close(); // This line is what is recommended in the documentation 

以下是它在文档中显示的内容:

 cz.msebera.android.httpclient.HttpEntity @java.lang.Deprecated public abstract void consumeContent() throws java.io.IOException This method is deprecated since version 4.1. Please use standard java convention to ensure resource deallocation by calling InputStream.close() on the input stream returned by getContent()