Java HttpsServer:在第一个成功请求之后连接超时

时间:2019-07-14 11:36:31

标签: java curl https keep-alive

我正在尝试在Java程序中添加一个小型Web服务器,以将内部数据提供给grafana服务器进行绘图。我遇到了内部HttpsServer类,并将其设置为确实可以提供所需内容。

现在,我正在命令行上使用curl测试程序。它按预期服务第一个请求。但是,如果我尝试第二次运行curl命令,则会遇到超时。然后,我需要杀死我的Java应用程序并重新启动它。只是这样,它在一次成功请求后便停止工作。

我在创建HttpsServer时尝试了“ backlog”选项。行为没有变化。

我在Google上搜索并找到了几个有关如何使用HttpsServer类的示例。我了解通过关闭OutputStream应该关闭连接/交换。我通过尝试在适当的地方尝试使用try / catch / finally来确保这一点。

在深入阅读它之后,我发现一条语句说一个人也应该始终使用完整的InputStream。所以我补充说-仍然是“破碎”的行为。

即使更改执行者,我也可以重现该问题。也就是说,例如,如果我使用5的固定线程池-curl会一直挂在第六个连接上。

一个似乎可行的令人讨厌的东西是Exchange处理程序末尾的Thread.getCurrentThread()。stop()。但是不仅不支持它,而且还不能可靠地运行(应用程序是在无法运行的Windows上开发的;在树莓派零(Linux)上无头运行,而Thread.stop似乎可以运行...)

我在HttpHandler中添加了一个断点,该断点在第一个请求中触发,但在第二个请求中不触发。因此,我很确定这是我自己的代码之外的问题。

为了进行测试,我从服务器的处理程序/安装程序中删除了所有内容,并使代码尽可能基本。仍然挂在第二个请求上。

我想念什么吗?我需要关闭其他东西吗?也许一些奇怪的保持生命的东西?也许套接字没有关闭,但也不能在第二个请求上重用?我宁愿不配置无尽的线程(即CachedThreadPool没有任何限制)。 HttpsServer对我来说不是正确的解决方案,我需要切换到underwow或JLHTTP之类的东西吗? 感谢您的帮助!

public class SimpleWebserver {

    private static final InetSocketAddress ADDRESS = new InetSocketAddress(8443);

    public static void main(String[] args) {
        try {
            // Initialise the HTTPS server
            HttpsServer httpsServer = HttpsServer.create(ADDRESS, 0);
            SSLContext sslContext = SSLContext.getInstance("TLS");

            // Initialise the keystore
            char[] password = "password".toCharArray();
            KeyStore ks = KeyStore.getInstance("JKS");
            FileInputStream fis = new FileInputStream("testkey.jks");
            ks.load(fis, password);

            // Set up the key manager factory
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, password);

            // Set up the trust manager factory
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ks);

            // Set up the HTTPS context and parameters
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
                @Override
                public void configure(HttpsParameters params) {
                    try {
                        // Initialise the SSL context
                        SSLContext c = SSLContext.getDefault();
                        SSLEngine engine = c.createSSLEngine();
                        params.setNeedClientAuth(false);
                        params.setCipherSuites(engine.getEnabledCipherSuites());
                        params.setProtocols(engine.getEnabledProtocols());

                        // Get the default parameters
                        SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
                        params.setSSLParameters(defaultSSLParameters);
                    } catch (Exception ex) {
                        Logger.getLogger(SimpleWebserver.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            });

            httpsServer.createContext("/", new SimpleHandler());
            //httpsServer.setExecutor(Executors.newFixedThreadPool(5));
            //httpsServer.setExecutor(Executors.newCachedThreadPool());
            httpsServer.setExecutor(null);
            httpsServer.start();

        } catch (Exception ex) {
            Logger.getLogger(SimpleWebserver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private static class SimpleHandler implements HttpHandler {

        @Override
        public void handle(HttpExchange he) throws IOException {
            HttpsExchange httpsExchange = (HttpsExchange) he;

            try {

                try (InputStream in = httpsExchange.getRequestBody()) {
                    byte[] buf = new byte[500];
                    while (in.read(buf) != -1) {
                    }
                }

                String response = "Hello World! \r\n";
                httpsExchange.sendResponseHeaders(200, response.getBytes().length);

                try (OutputStream os = httpsExchange.getResponseBody()) {
                    os.write(response.getBytes());
                }

            } finally {
                httpsExchange.close();
            }
        }

    }
}

我使用以下curl cmd测试服务器:

curl -v -H "Content-Type: application/json" -d '{"name":"Testing!"}' --insecure --no-keepalive --connect-timeout 5 https://localhost:8443

结果(第一个请求):

* Rebuilt URL to: https://localhost:8443/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (OUT), TLS change cipher, Client hello (1):
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS Unknown, Certificate Status (22):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS Unknown, Certificate Status (22):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using unknown / TLS_AES_256_GCM_SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=Unknown; ST=Unknown; L=Unknown; O=Unknown; OU=Unknown; CN=localhost
*  start date: Jul 11 19:57:54 2019 GMT
*  expire date: May 19 19:57:54 2029 GMT
*  issuer: C=Unknown; ST=Unknown; L=Unknown; O=Unknown; OU=Unknown; CN=localhost
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
* (304) (OUT), TLS Unknown, Unknown (23):
> POST / HTTP/1.1
> Host: localhost:8443
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 19
> 
* upload completely sent off: 19 out of 19 bytes
* (304) (IN), TLS Unknown, Certificate Status (22):
* (304) (IN), TLS handshake, Newsession Ticket (4):
* (304) (IN), TLS Unknown, Unknown (23):
< HTTP/1.1 200 OK
< Date: Sun, 14 Jul 2019 11:27:15 GMT
< Content-length: 15
< 
* (304) (IN), TLS Unknown, Unknown (23):
Hello World! 
* Connection #0 to host localhost left intact

第二次运行:

* Rebuilt URL to: https://localhost:8443/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* (304) (OUT), TLS handshake, Client hello (1):
* Operation timed out after 5000 milliseconds with 0 out of 0 bytes received
* stopped the pause stream!
* Closing connection 0
curl: (28) Operation timed out after 5000 milliseconds with 0 out of 0 bytes received

0 个答案:

没有答案