java - 使用 sun.net.www.protocol.http.HttpURLConnection.getInputStream() 的偶发连接问题的根本问题是什么?

标签 java http tomcat request

我的问题与this, as yet unanswered, StackOverflow question 非常相似关于神秘的连接问题。有时(仅在特定环境中的特定条件下,特别是当尝试从 AWS 访问一个特定 URL 时)http 连接始终失败,没有明显的原因。

背景:

我已经能够在 2 个 AWS EC2 服务器环境中重现它(虽然我无法在本地重现它),但只有在尝试访问一个特定客户的网络服务 URL 时(所有其他运行类似服务的 URL 都可以正常工作)。

我的 Java 版本:

# java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)

我试图攻击的机器运行一个 RESTful 网络服务(在 Tomcat 中,可能在 Windows 机器上以 Apache 为前端)。我可以 curl 我的代码试图从我的代码运行的实例命中的相同端点,并在 ~48-120 毫秒内获得有效响应。从代码中,我达到了配置的 10 秒超时。从两台机器上运行 netstat 显示我的服务器的以下内容(我正在发出请求):

$ netstat -cowtune | grep <remote_ip>
tcp        0    389 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   ESTABLISHED 501        33146      on (0.08/2/0)
tcp        0    389 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   ESTABLISHED 501        33146      on (0.22/3/0)
tcp        0    389 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   ESTABLISHED 501        33146      on (1.50/4/0)
tcp        0    389 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   ESTABLISHED 501        33146      on (0.48/4/0)
tcp        0    389 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   ESTABLISHED 501        33146      on (4.07/5/0)
tcp        0    389 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   ESTABLISHED 501        33146      on (3.05/5/0)
tcp        0    389 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   ESTABLISHED 501        33146      on (2.03/5/0)
tcp        0    389 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   ESTABLISHED 501        33146      on (1.00/5/0)
tcp        0    389 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   ESTABLISHED 501        33146      on (18446744073.69/5/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (8.20/6/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (7.18/6/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (6.15/6/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (5.13/6/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (4.11/6/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (3.09/6/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (2.07/6/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (1.05/6/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (0.03/6/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (17.46/7/0)
tcp        0    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   FIN_WAIT1   0          0          on (16.44/7/0)

tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0              0          on (15.42/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (14.39/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (13.37/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (12.35/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (11.33/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (10.31/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (9.29/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (8.27/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (7.25/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (6.23/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (5.21/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (4.19/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (3.17/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (2.15/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (1.13/7/0)
tcp        1    390 ::ffff:10.91.184.202:40153  ::ffff:<remote_ip>:<port>   CLOSING     0          0          on (0.11/7/0)

这来自远程服务器(我正在向其发出请求):

D:\Cygwin>netstat -ant 1 | grep 54.81.126.17
TCP    <ip_address>:<port>    54.81.126.17:40153    SYN_RECEIVED    InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    ESTABLISHED     InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    ESTABLISHED     InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    ESTABLISHED     InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    ESTABLISHED     InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    ESTABLISHED     InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    ESTABLISHED     InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    ESTABLISHED     InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    ESTABLISHED     InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    ESTABLISHED     InHost

TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost
TCP    <ip_address>:<port>    54.81.126.17:40153    FIN_WAIT_2      InHost

在我配置的 10 秒超时时,我的服务器显示从 ESTABLISHEDFIN_WAIT_1 的转换。一段时间后,我的服务器显示从 FIN_WAIT_1CLOSING 的转换,同时远程服务器从 ESTABLISHED 转换到 FIN_WAIT_2 。远程 Tomcat 从不注册接收请求。 TShark 显示:

0.000000 10.182.160.132 -> <remote_ip> TCP 74 49486 > http-alt [SYN] Seq=0 Win=14600 Len=0 MSS=1460 SACK_PERM=1 TSval=1814494 TSecr=0 WS=128
0.035580 <remote_ip> -> 10.182.160.132 TCP 70 http-alt > 49486 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1380 SACK_PERM=1 TSval=101011325 TSecr=1814494
0.035601 10.182.160.132 -> <remote_ip> TCP 66 49486 > http-alt [ACK] Seq=1 Ack=1 Win=14600 Len=0 TSval=1814503 TSecr=101011325
0.035935 10.182.160.132 -> <remote_ip> HTTP 457 POST /service/rest/security/myEndpoint HTTP/1.1
0.171137 10.182.160.132 -> <remote_ip> HTTP 457 [TCP Retransmission] POST /service/rest/security/myEndpoint HTTP/1.1
0.443125 10.182.160.132 -> <remote_ip> HTTP 457 [TCP Retransmission] POST /service/rest/security/myEndpoint HTTP/1.1
0.987118 10.182.160.132 -> <remote_ip> HTTP 457 [TCP Retransmission] POST /service/rest/security/myEndpoint HTTP/1.1
2.079144 10.182.160.132 -> <remote_ip> HTTP 457 [TCP Retransmission] POST /service/rest/security/myEndpoint HTTP/1.1
4.263141 10.182.160.132 -> <remote_ip> HTTP 457 [TCP Retransmission] POST /service/rest/security/myEndpoint HTTP/1.1
8.631153 10.182.160.132 -> <remote_ip> HTTP 457 [TCP Retransmission] POST /service/rest/security/myEndpoint HTTP/1.1
10.036939 10.182.160.132 -> <remote_ip> TCP 66 49486 > http-alt [FIN, ACK] Seq=392 Ack=1 Win=14600 Len=0 TSval=1817003 TSecr=101011325
10.072638 <remote_ip> -> 10.182.160.132 TCP 66 [TCP Window Update] http-alt > 49486 [ACK] Seq=1 Ack=1 Win=64296 Len=0 TSval=101012329 TSecr=1814503
17.351131 10.182.160.132 -> <remote_ip> HTTP 457 [TCP Retransmission] POST /service/rest/security/myEndpoint HTTP/1.1
20.584358 <remote_ip> -> 10.182.160.132 TCP 66 http-alt > 49486 [FIN, ACK] Seq=1 Ack=1 Win=64296 Len=0 TSval=101013380 TSecr=1814503
20.584421 10.182.160.132 -> <remote_ip> TCP 66 49486 > http-alt [ACK] Seq=393 Ack=2 Win=14600 Len=0 TSval=1819640 TSecr=1

我的旧代码:

InputStream getResponseStream(String webServiceUrl) {
  URL server = new URL(webServiceUrl);
  HttpURLConnection connection = (HttpURLConnection) server.openConnection();
  connection.setDoInput(true);
  connection.setDoOutput(true);
  connection.setRequestMethod("GET");
  return connection.getInputStream(); // timeout happens here
}

我更好的代码(这个和下面):

private Object getResponse(HttpURLConnection connection,
        SdRestResponseType respType) throws IOException, JAXBException,
        ProtocolException {
    InputStream is = null;
    try {
        // check if valid response
        int responseCode = connection.getResponseCode(); // timeout happens here
        if (responseCode == HttpURLConnection.HTTP_OK) {
            is = connection.getInputStream();
            switch (respType) {
            case BOOLEAN:
                return Boolean.valueOf(readInput(is));
            case STRING:
                return readInput(is);
            case XML:
                Unmarshaller unmarshaller = context.createUnmarshaller();
                return unmarshaller.unmarshal(is);
            default:
                return null;
            }
        }

        is = connection.getErrorStream();
        Unmarshaller unmarshaller = context.createUnmarshaller();
        Object response = unmarshaller.unmarshal(is);

        if (response instanceof Fault) {
            throw new SdFaultException((Fault) response);
        }
        throw new ProtocolException(connection.getResponseMessage());

    } finally {
        if (is != null) {
            is.close();
        }
    }
}

创建执行请求的 HttpURLConnection 对象的代码位:

private HttpURLConnection getConnection(String operation, boolean xmlContent)
        throws IOException {

    URL server = new URL(baseUrl + operation);
    HttpURLConnection connection = (HttpURLConnection) server
            .openConnection();
    connection.setDoInput(true);
    connection.setDoOutput(true);
    connection.setReadTimeout(10000);
    connection.setRequestMethod(POST); // the remote endpoint accepts this request as either a GET or POST just fine, except from this code
    connection.setRequestProperty(CONTENT_TYPE, (xmlContent ? XML_ENCODED
            : URL_ENCODED));
    // set header values
    connection.addRequestProperty(CLIENT_ID, header.getClientID());
    if (header.getLocale() != null) {
        connection.addRequestProperty(LOCALE, header.getLocale());
    }
    if (header.getSessionToken() != null) {
        connection.addRequestProperty(SESSION, header.getSessionToken());
    }
    if (this.passthrough != null) {
        connection.addRequestProperty(PASSTHRU, this.passthrough);
    }

    return connection;
}

我的服务器(FROM 框)正在运行 Linux、Apache 和我在 Tomcat 中的应用程序。所有 DNS 查找都没有意外。盒子之间的连接似乎在所有其他方面都是正常的(我没有详尽地检查我的iptables 配置)。当我逐步执行代码时,一切看起来都很正常,直到执行消失到 sun.net.www.protocol.http.HttpURLConnection.getInputStream() 的编译代码中。

In GrepCode's OpenJDK source ,第 710 行显示 IOException 被吞噬,但由于 Oracle 版本源是专有的(因此我发现的任何地方都不可用)我想知道是否有人知道(或可以指出)引擎盖下可能发生的事情,因为我还不能完全排除服务器环境出现问题的可能性。

提前感谢您的任何见解!

最佳答案

回答我自己的?:

永远不要相信他们的 IT 员工。

经过双重/三重检查后,事实证明远程服务器有一个活跃的入侵检测系统,阻止所有未知的 IP 地址。由于 AWS 实例在循环时可以更改其 IP,即使它们将已知 IP 列入白名单,它也只能在我的实例被弹回之前起作用。经验教训:在询问“你能阻止我们吗?”时要具体得令人作呕

为什么他们允许 curl 通过仍然是个谜,直到我收到回复电子邮件以更新此答案......

关于java - 使用 sun.net.www.protocol.http.HttpURLConnection.getInputStream() 的偶发连接问题的根本问题是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22623188/

相关文章:

java - 使用 servlet 3.1 异步 io 有什么真正的好处?

tomcat - quartz : Memory Leak?

java - <T extends Comparable> implements Comparable<Transition <T>> 的 C# 等价物是什么?

java - 大数减法

javascript - 如何向 bitstamp 发出 HTTP 请求?

http - 什么是 Web 服务器端超时?

java - Java中检查匹配文件的有效方法

java - 如何在应用程序中始终保持框架在顶部,但在使用 Java 中的其他应用程序时将其置于后台?

过期链接的http状态代码?

java - tomcat是如何解析资源的?