2012-03-29 93 views
20

我正在开发一个长时间运行的应用程序,大量使用来自Apache的HttpClient。HttpClient卡住没有任何异常

在我的第一次测试运行中,应用程序工作完美,直到它卡住了。它没有停止,它没有抛出任何异常,它只是坐在那里无所事事。

我刚刚做了第二次运行,并停止了时间,大约在第二次运行后停止。 24小时运行。此外,我注意到我运行的笔记本电脑的互联网连接在应用程序卡住的时刻终止。我必须重新启动我的WLAN适配器才能再次运行网络。

虽然应用程序在连接重新启动后没有恢复工作。而现在,它又被卡住了。

是否有任何超时控制器,我不知道在HttpClient中?为什么我的应用程序在连接断开时不会引发异常?

使用客户端的部分如下所示;

public HttpUtil(ConfigUtil config) { 
    this.config = config; 

    client = new DefaultHttpClient(); 
    client.getParams().setParameter(HttpProtocolParams.USER_AGENT, this.config.getProperty("httputil.userAgent")); 
} 

public String getContentAsString(String url) throws ParseException, ClientProtocolException, IOException { 
    return EntityUtils.toString(
      client.execute(
        new HttpGet(url)).getEntity()); 
} 

该应用程序在需要的URL上重复调用httputil.getContentAsString()

+0

也许你的实体是一个空字符串。 – kasavbere 2012-03-29 12:20:11

+0

然后我的方法仍然会返回那个空字符串,不是吗?或者至少抛出异常? – 2012-03-29 12:31:37

+1

我有同样的问题。 httpEntity.consumeContent()救我。 http://stackoverflow.com/questions/9505358/android-httpclient-hangs-on-second-request-to-the-server-connection-timed-out – JamesC 2015-02-25 08:57:29

回答

8

此代码现已被弃用(获得HttpParams等)。更好的方法是:

RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.BEST_MATCH).setExpectContinueEnabled(true).setStaleConnectionCheckEnabled(true).setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST)).setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build(); 

HttpGet httpGet = new HttpGet(url);  
RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig).setSocketTimeout(5000).setConnectTimeout(5000).setConnectionRequestTimeout(5000).build(); 
httpGet.setConfig(requestConfig); 
6

你还没有说过你正在使用哪个版本的HttpClient,但假设它是版本4,this blog article解释了该怎么做。

DefaultHttpClient httpClient = new DefaultHttpClient(); 
HttpParams params = httpClient.getParams(); 
HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeoutMillis); 
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis); 
+2

我相信这是现在不推荐使用 – 2014-12-11 16:23:50

3

默认情况下,HttpClient不超时(这会导致更多的问题,而不是帮助)。你所描述的可能是一个硬件问题,如果你的网络适配器死了,HttpClient会挂起。

下面是parameters设置为HttpParams作为构造的一部分,以DefaultHttpClient包括

http.socket.timeout:定义插座超时(SO_TIMEOUT)在 毫秒,这是等待超时对于数据或者以不同的方式,将两个连续数据分组之间的最大周期不活动性)分组。超时值为零被解释为无限的 超时。该参数需要java.lang.Integer类型的值。如果 未设置此参数,则读操作不会超时(无限 超时)。

这将在连接上设置一个超时,所以在设置超时之后会抛出一个异常。

3

我所有的超时设置得很好,但我发现我们有URL,做HTTP分块,不发送结果(铬工作正常,但在HTTP客户端甚至与超时设置永远挂起)。幸运的是,我拥有服务器,只是返回一些垃圾,它不再挂起。这似乎是一个非常独特的错误,因为http客户端并没有很好地处理某种空块(尽管我可能会离开)....我只知道它每次都挂在同一个具有空数据的url上,并且该url是http chunking csv下载回我们的http客户端。

6

从版本4.4开始,用户user2393012和Stephen C的答案都已被弃用。我不确定是否有另一种方式来完成它,但我这样做的方式是使用构建器范例HTTPClientBuilder。

Ex。

HttpClients.custom().setConnectionTimeToLive(1, TimeUnit.MINUTES).build() 

非常相似(它实际上可能是OP的问题)问题是什么OP也提到,但发生是由于Apache的默认并发连接数设置为每个客户端只有两个连接。解决方法是增加最大连接数或者如果可以的话关闭它们。

要增加最大连接数:

HttpClients.custom().setMaxConnPerRoute(100000).build() 

关闭连接,你可以使用一个BasicHttpClientConnectionManager并呼吁关闭方法

3

我有同样的问题,它坚持,因为我没有关闭DefaultHttpClient。
因此,这是错误的:

try{ 
    DefaultHttpClient httpclient = new DefaultHttpClient(); 
    ... 
} catch (Exception e){ 
    e.PrintStackTrace(); 
} 

这是正确的:

try (DefaultHttpClient httpclient = new DefaultHttpClient()){ 
    ... 
} catch (Exception e){ 
    e.PrintStackTrace(); 
} 

希望它可以帮助别人。

4

我在另一个线程(HttpClient hangs on socketRead0 with successfully executed method

在我的情况,我设置为ConnectionTimeout和了socketTimeout上的要求,但不建立SSL连接时使用的连接插座上给出了类似的回答。因此,我有时会在SSL握手期间挂起。下面是一些使用v4.4设置所有3个超时的代码(也在v4.5中测试过)

// Configure the socket timeout for the connection, incl. ssl tunneling 
connManager = new PoolingHttpClientConnectionManager(); 
connManager.setMaxTotal(200); 
connManager.setDefaultMaxPerRoute(100); 

SocketConfig sc = SocketConfig.custom() 
    .setSoTimeout(soTimeoutMs) 
    .build(); 

connManager.setDefaultSocketConfig(sc); 

HttpClient client = HttpClients.custom() 
      .setConnectionManager(connManager) 
      .setConnectionManagerShared(true) 
      .build(); 

// configure the timeouts (socket and connection) for the request 
RequestConfig.Builder config = = RequestConfig.copy(RequestConfig.DEFAULT); 
config.setConnectionRequestTimeout(connectionTimeoutMs); 
config.setSocketTimeout(socketTimeoutMs); 

HttpRequestBase req = new HttpGet(uri); 
req.setConfig(config.build()); 

client.execute(req);