HttpsURLConnection - 间歇连接拒绝错误

时间:2013-12-19 22:35:15

标签: java multithreading sockets tcpdump httpsurlconnection

我通过java应用程序和HttpsURLConnection实现连接到Web服务。我打开连接,使用try with resource block打开(并在完成时关闭)输入流和输入流读取器,然后在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强制完全断开连接,或者在调用disconnect时通过服务器设置强制完全断开连接?或者是一种让它更快发生的方法,从而减少错误的可能性?我可以重试连接,直到它成功连接,但这似乎是一个黑客。

任何人都可以帮我指出正确的方向吗?

更新 - 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...

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:-1)

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

这可以被服务器粗略地禁用,使得HTTP客户端库无法确定它何时完成发送数据,即不发送Content-Length头而不使用chunked编码。然而,许多Web框架会自动执行一个或另一个 - 并且应用程序可能仍然依赖它们,因为客户端应用程序仍然必须确定服务器何时完成数据发送,并且它可能依赖于Content-Length或chunked encoding确定这个!

但是,连接拒绝错误不太可能与此现象有关 - 事实上,HTTP Keepalive应该使更少可能会发现连接被拒绝错误,而不是更多,因为它重用现有连接。

相关问题