【问题标题】:HttpsURLConnection - Intermittent Connection Refused errorsHttpsURLConnection - 间歇性连接被拒绝错误
【发布时间】:2013-12-19 22:35:15
【问题描述】:

我正在通过 java 应用程序和 HttpsURLConnection 实现连接到 Web 服务。我打开连接,使用资源块尝试打开(并在完成后关闭)输入流和输入流阅读器,然后在 finally 块中调用 connection.disconnect 。代码如下,它大部分时间都有效。

    HttpsURLConnection connection = null;
    try{       
         // basic authentication
        String encodedAuthString =
            DatatypeConverter.printBase64Binary((userName + ":" + password)
                .getBytes());   

        connection = (HttpsURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setRequestProperty("Authorization", "Basic " + encodedAuthString);

        //try-with-resource to close connections when complete
        try(InputStream in = connection.getInputStream();
            InputStreamReader isr = new InputStreamReader(in)){
            int numCharsRead;
            char[] charArray = new char[1024];
            StringBuffer sb = new StringBuffer();
            while ((numCharsRead = isr.read(charArray)) > 0) {
                sb.append(charArray, 0, numCharsRead);
            }

            jsonResult = sb.toString();
        }

    } 
    catch (Exception e){
        throw e;
    } finally {
        if(connection!= null)
            connection.disconnect();
    }

然而,这段代码可以在一秒钟内被多个线程调用多次(虽然实际的包含方法是同步的,所以一次只有一个线程可以访问连接)。在与我们的网络人员合作时,我们发现即使应用程序调用了“connection.disconnect()”,服务器上的连接也不会立即断开。我们在服务器日志中看到断开连接的调用,但 java 应用程序在服务器完全断开连接之前尝试再次连接,导致“连接被拒绝错误”。

在再次连接之前是否可以通过 java 强制完全断开连接,或者在调用断开连接时通过服务器设置强制断开连接?或者有一种方法让它发生得更快,从而减少出错的可能性?我可以重试连接,直到它成功连接,但这似乎是一个 hack。

谁能帮我指出正确的方向?

更新 - 2013 年 1 月 6 日 - 随着我继续调查,我通过阅读 tcpdump 发现我的客户端在同一端口上连接了 100 个请求,然后是第 101 个请求,端口更改,我收到错误。连接最终将恢复并开始在新端口上发送和接收请求,但可能需要一分钟才能恢复。我在下面包含了 tcpdump。可以看到,当客户端在新端口上发送时,目标 ip 在新端口上返回一个“R”eset。因此,我认为该错误是目的地错误而不是来自我的客户的错误的结果,但我仍在尝试验证,因为我对此级别的理解有限。

13:20:25.925760 IP DESTINATION_IP.https > CLIENT_IP.53321: P 197809:197846...
13:20:25.925819 IP CLIENT_IP.53321 > DESTINATION_IP.https: . ack 197846 wi...
13:20:25.926393 IP CLIENT_IP.53321 > DESTINATION_IP.https: P 82874:82911(3...
13:20:25.926424 IP CLIENT_IP.53321 > DESTINATION_IP.https: F 82911:82911(0...
13:20:25.928629 IP CLIENT_IP.53322 > DESTINATION_IP.https: S 702514925:702...
13:20:26.005902 IP DESTINATION_IP.https > CLIENT_IP.53321: . ack 82911 win...
13:20:26.008461 IP DESTINATION_IP.https > CLIENT_IP.53322: R 0:0(0) ack 70...
13:20:26.011274 IP DESTINATION_IP.https > CLIENT_IP.53321: P 197846:197883...
13:20:26.011290 IP CLIENT_IP.53321 > DESTINATION_IP.https: R 494623963:494...
13:20:26.011300 IP DESTINATION_IP.https > CLIENT_IP.53321: F 197883:197883...
13:20:26.011305 IP CLIENT_IP.53321 > DESTINATION_IP.https: R 494623963:494...

【问题讨论】:

    标签: java multithreading sockets tcpdump httpsurlconnection


    【解决方案1】:

    摆脱 disconnect() 调用。这会阻止 HTTP keepalive 工作。因此,您正在使用更多的 TCP 连接,这会填满服务器上的积压队列,从而导致连接拒绝(在某些平台上)。在大多数情况下,关闭输入流就足够了。

    【讨论】:

    • 感谢您的回复。我已经删除了断开连接,它没有任何区别。但是,我通过阅读 tcpdump 发现了更多信息,并用其他信息更新了我原来的问题。
    【解决方案2】:

    由于 HTTP Keep Alive,连接保持活动状态。

    这可以被服务器粗略地禁用,使得 HTTP 客户端库无法确定它何时完成发送数据,即不发送 Content-Length 标头并且也不使用分块编码。然而,许多 Web 框架会自动执行其中的一项 - 并且应用程序可能无论如何都依赖它们,因为客户端应用程序仍然必须确定服务器何时完成发送数据,并且它可能依赖于 Content-Length 或分块编码之类的东西确定这一点!

    但是,连接被拒绝错误不太可能与这种现象有关 - 事实上 HTTP Keepalive 应该较少您会看到连接被拒绝错误,而不是更多,因为它重用了现有的连接。

    【讨论】:

    • 没有。 disconnect() 调用阻止了连接保持活动状态。那就是问题所在。启用 keepalive 是解决方案,而不是问题。
    猜你喜欢
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多