【问题标题】:HttpClient hangs on socketRead0 with successfully executed methodHttpClient 挂在 socketRead0 上并成功执行了方法
【发布时间】:2013-03-30 06:47:41
【问题描述】:

在我们的网络应用程序中,用户可以提交一个 url。我们将获取数据并在服务器端解析它。对于每个请求,我们使用具有以下(相关)设置的 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 )

我无法找到发生这种情况的确切 URL(是在现场环境中发生的事件),并且我无法重现它。我想这只是我们连接的服务器行为异常的问题,但也许我错过了一些东西。在任何一种情况下,我有没有办法防止阻塞方法调用永远等待? SoTimeout 也是套接字读取超时?我还缺少其他设置吗?

【问题讨论】:

    标签: java sockets timeout httpclient


    【解决方案1】:

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

    【讨论】:

    • setConnectTimeout != setConnectionRequestTimeout 并且没有setConnectionTimeout
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • @Dean Hiller:这毫无意义。套接字超时适用于套接字读取操作,与任何 HTTP 协议元素无关。如果您仍然可以重现此问题,请使用 HC 项目提出 JIRA 并提交显示问题的会话的电报日志。
      • 我同意你的观点,根据我的经验,超时通常有效......可能是我搞砸的其他事情,但返回数据解决了问题。
      【解决方案4】:

      我们在我们的实现中始终如一地看到这一点,看起来 http 客户端没有正确处理错误的服务器或其他东西并且它没有超时.....我可以使用这个数据总线开源项目和堆栈在我们的设置中重现trace 有点不同...

      SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) 行:不可用 [本机方法]
      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() 行:96
      ReadAggregations.main(String[]) 行:70

      【讨论】:

      • 我今天仍然面临这个问题。你知道 apache httpclient 的任何替代品不会挂在坏的服务器上吗?
      • @Arya 我最终在这里写了一个 http1.1 客户端和一个 http2 客户端github.com/deanhiller/webpieces(这是一大堆网页)。这是非常测试版,但有一个独特的背压功能(由于某种原因,现在需要在客户端中关闭它......因为我正在处理那个错误)。附言。它看起来只是一个网络服务器,但网络服务器建立在与客户端相同的 http 解析器、相同的 nio 层等之上,并且客户端是异步的。虽然它是测试版,但它是为测试而编写的
      • @Arya 来完成那句话,就像这样blog.twitter.com/engineering/en_us/topics/insights/2017/… 注意:网络服务器的测试比客户端测试的要多(最终测试 http 解析器),但我碰巧在客户端上工作最近。
      • @Arya 哈哈,天哪,我完全忘记了,还有一个 http2to1_1-client 意味着您处理 http2 对象并通过 http1.1 协议进行通信,以便它与 http2 客户端交换 1 对 1 . (即,API 是相同的)。我忘了我是这样做的。哈哈。我一直在记录网络服务器,但到目前为止还没有记录客户端:(所以我仍然需要这样做,尽管没有太多内容,因为对象是 1 对 1 的,协议让客户端只处理传入的对象然后出去。
      【解决方案5】:

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

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

      HttpMethod.getResponseBody

      被顺序调用或者应该为改变状态码的部分使用互斥体(信号量)

      您还应该减少超时限制以防止挂起。

      【讨论】:

      • 检查方法是否成功并获得响应发生在同一个线程上。不存在并发问题。 HttpClient 获取并更新状态。呼叫无限期挂起,不遵守提及的超时,更改它没有效果。
      • 我的情况更糟,并且在线程应用程序中每次都会发生,尽管在它发生之前需要 800 次左右的调用,所以调试起来真的很痛苦....顺便说一下,它挂在一个通常是块的调用上数据返回(http 分块),但是这个调用是由于某种原因还没有数据的地方 http 客户端挂起....可能是服务器做错了,尽管我在 chrome 中手动尝试了 url 并且它工作正常......只有 http客户正在为此苦苦挣扎。
      • 我发布了非常接近的堆栈跟踪
      猜你喜欢
      • 2014-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多