我正在尝试在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