我正在努力解决以下问题:
我的应用程序使用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();
}
}