0

我正在通过 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...
4

2 回答 2

0

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

于 2014-01-05T22:06:28.047 回答
-1

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

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

然而,连接被拒绝错误不太可能与这种现象有关——事实上,HTTP Keepalive 应该使您看到连接被拒绝错误的可能性降低,而不是更多,因为它重用了现有连接

于 2013-12-19T22:40:57.243 回答