HttpClient在成功执行的方法上挂起socketRead0

时间:2013-04-08 08:45:24

标签: java sockets timeout httpclient

在我们的网络应用程序中,用户可以提交网址。我们将获取数据并解析服务器端。对于每个请求,我们使用具有以下(相关)设置的HttpClient

connectionManager.getParams().setConnectionTimeout(10000);
connectionManager.getParams().setSoTimeout(10000);

当我调用HttpMethod.getResponseBody时,状态代码已被检查为可接受。此时,线程将挂起此堆栈跟踪:

java.net.SocketInputStream.socketRead0 ( native code )
java.net.SocketInputStream.read ( SocketInputStream.java:150 )
java.net.SocketInputStream.read ( SocketInputStream.java:121 )
java.io.BufferedInputStream.read1 ( BufferedInputStream.java:273 )
java.io.BufferedInputStream.read ( BufferedInputStream.java:334 )
java.io.FilterInputStream.read ( FilterInputStream.java:133 )
org.apache.commons.httpclient.AutoCloseInputStream.read ( AutoCloseInputStream.java:108 )
java.io.FilterInputStream.read ( FilterInputStream.java:107 )
org.apache.commons.httpclient.AutoCloseInputStream.read ( AutoCloseInputStream.java:127 )
org.apache.commons.httpclient.HttpMethodBase.getResponseBody ( HttpMethodBase.java:690 )

我无法找到发生这种情况的确切网址(这是在实时环境中发生的事件)而且我无法重现它。我想这只是我们所连接的服务器的一个问题,表现得很奇怪,但也许我错过了一些东西。在任何一种情况下,有没有办法让我阻止阻塞方法调用永远等待? SoTimeout也是套接字读取超时?我还缺少另一种设置吗?

5 个答案:

答案 0 :(得分:3)

我已经将所有超时设置得很好但是我发现我们在url上进行了http分块但没有发送结果(在chrome中运行正常,但在http客户端中它甚至会在超时设置下永久挂起)。幸运的是,我拥有服务器,只是返回一些垃圾,它不再挂起。这似乎是一个非常独特的错误,http客户端不能很好地处理某种空的分块情况(虽然我可能会离开)....我只是知道它每次挂在同一个网址上的空数据和该网址是http chunking csv下载回我们的http客户端。

答案 1 :(得分:0)

  

当我调用HttpMethod.getResponseBody时,状态代码已被检查为可接受。此时线程挂起

看起来您在同步调用时遇到问题......您应该确保方法

  

HttpMethod.getResponseBody

按顺序调用,或者应该使用互斥(信号量)作为更改状态代码的部分

此外,您应该减少超时限制以防止挂起。

答案 2 :(得分:0)

我们在实现中始终看到这一点,看起来http客户端没有正确处理坏服务器或其他东西而且它没有超时.....我可以在我们的设置中使用此数据库开源项目和堆栈重现跟踪有点不同......

SocketInputStream.socketRead0(FileDescriptor,byte [],int,int,int)行:不可用[native method]
SocketInputStream.read(byte [],int,int)行:129
SocketInputBuffer(AbstractSessionInputBuffer).fillBuffer()行:166
SocketInputBuffer.fillBuffer()行:90 SocketInputBuffer(AbstractSessionInputBuffer).readLine(CharArrayBuffer)行:281
DefaultHttpResponseParser.parseHead(SessionInputBuffer)行:92
DefaultHttpResponseParser.parseHead(SessionInputBuffer)行:62
DefaultHttpResponseParser(AbstractMessageParser).parse()行:254
DefaultClientConnection(AbstractHttpClientConnection).receiveResponseHeader()行:289 DefaultClientConnection.receiveResponseHeader()行:252
BasicPooledConnAdapter(AbstractClientConnAdapter).receiveResponseHeader()行:219 HttpRequestExecutor.doReceiveResponse(HttpRequest,HttpClientConnection,HttpContext)行:300 HttpRequestExecutor.execute(HttpRequest,HttpClientConnection,HttpContext)行:127
DefaultRequestDirector.tryExecute(RoutedRequest,HttpContext)行:712 DefaultRequestDirector.execute(HttpHost,HttpRequest,HttpContext)行:517
DefaultHttpClient(AbstractHttpClient).execute(HttpHost,HttpRequest,HttpContext)行:906 DefaultHttpClient(AbstractHttpClient).execute(HttpUriRequest,HttpContext)行:805
ReadAggregations.processAggregation(String,Counter,Counter,Counter,Counter)行:153
ReadAggregations.start()line:96
ReadAggregations.main(String [])line:70

答案 3 :(得分:0)

您可以尝试使用HttpUriRequest#abort()中止请求,请参阅https://hc.apache.org/httpcomponents-client-4.3.x/httpclient/apidocs/org/apache/http/client/methods/HttpUriRequest.html#abort%28%29。但是,设置一个不需要拦截的timemout会更好。 以下是相关问题:Setting time out in apache http client

答案 4 :(得分:0)

HttpClient区分连接和请求。 setSoTimeout将配置连接套接字超时,而setConnectionTimeout将配置连接管理器的超时(等待连接的时间)以及建立连接本身。在您提供的代码中,您没有为请求本身使用的套接字设置任何超时,不幸的是,HttpClient默认没有超时。

这是我在v4.4.1中的表现:

// 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);