Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java HttpClient挂起在socketRead0上,方法已成功执行_Java_Sockets_Timeout_Httpclient - Fatal编程技术网

Java HttpClient挂起在socketRead0上,方法已成功执行

Java HttpClient挂起在socketRead0上,方法已成功执行,java,sockets,timeout,httpclient,Java,Sockets,Timeout,Httpclient,在我们的web应用程序中,用户可以提交url。我们将获取数据并在服务器端对其进行解析。对于每个请求,我们使用具有以下(相关)设置的HttpClient 当我调用HttpMethod.getResponseBody时,状态代码已被检查为可接受。此时,线程将挂起此堆栈跟踪: java.net.SocketInputStream.socketRead0 ( native code ) java.net.SocketInputStream.read ( SocketInputStream.java:15

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

当我调用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 )
我无法发现发生这种情况的确切URL(这是一个在实时环境中发生的事件),我无法复制它。我想这只是我们连接到的服务器行为异常的问题,但也许我遗漏了什么。在这两种情况下,有没有办法防止阻塞方法调用永远等待?SoTimeout也是套接字读取超时?我还缺少其他设置吗

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

看起来您在同步呼叫方面有问题。。。您应该确保该方法

HttpMethod.getResponseBody

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


您还应该降低超时限制以防止挂起。

我们在实现中一致地看到了这一点,看起来http客户端没有正确地处理坏服务器或其他什么,并且没有超时……我可以使用此databus开源项目在我们的设置中重现,堆栈跟踪略有不同

SocketInputStream.socketRead0(文件描述符,字节[],int,int,int)行:不可用[本机方法]
SocketInputStream.read(字节[],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).receiverResponseHeader()行:289 DefaultClientConnection.ReceiverResponseHeader()行:252
BasicPooledConnAdapter(AbstractClientConnAdapter)。ReceiverResponseHeader()行: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(字符串、计数器、计数器、计数器)行:153
ReadAggregations.start()行:96

ReadAggregations.main(String[])行:70

我所有的超时设置都很好,但我发现我们的url上有http分块但不发送结果(在chrome中工作正常,但在http客户端,即使设置了超时,它也会永远挂起)。幸运的是,我拥有服务器,只返回一些垃圾,它不再挂起。这似乎是一个非常独特的错误,因为http客户端无法很好地处理某种类型的空分块情况(尽管我可能有点不对劲)…我只知道它每次都挂在同一个url上,带有空数据,该url是http分块csv下载回http客户端。

您可以尝试使用HttpUriRequest#abort()中止请求,请参阅。但是,设置一个不需要拦截的timemout会更好。
这里有一个相关的问题:

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

检查方法是否成功并在同一线程上获得响应。不存在并发问题。HttpClient获取并更新状态。调用无限期挂起,提及超时不受尊重,更改它没有任何效果。我的情况更糟,而且在线程化应用程序中每次都会发生,尽管它需要800个左右的调用才能发生,所以调试是一件非常痛苦的事……顺便说一句,它挂起的调用通常会将数据分块返回(http分块)但这一次调用是由于某种原因,http客户端挂起而没有数据的地方…可能是服务器做错了什么,尽管我在chrome中手动尝试了url,但效果很好…只有http客户端正在努力解决它。我发布了我们的堆栈跟踪,这非常有用close@Dean希勒:这毫无意义。套接字超时适用于套接字读取操作,与任何HTTP协议元素都不相关。如果您仍然可以重现此问题,请向HC项目提交JIRA,并提交显示此问题的会话的有线日志。我同意您的观点,并且根据我的经验,超时通常有效…可能是我搞砸了,但返回数据修复了此问题。
setConnectTimeout
!=
setConnectionRequestTimeout
并且没有
setConnectionTimeout
我今天仍然面临这个问题。你知道ApacheHttpClient有什么替代品可以不挂在坏服务器上吗?@Arya我最后在这里编写了一个http1.1客户端和一个http2客户端(这是一大堆Web文章)。这是非常测试版,但有一个独特的背压功能(出于某些原因需要右转)
// 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);