多线程 Java HTTP 服务器
Multi-Threaded Java HTTP-Server
我在我的应用程序中使用 sun.net.httpServer
到 运行 HTTP 服务器(不要问我为什么)。
问题是它只在一个线程中处理我的请求,所以我的吞吐量是一场灾难。
我想如果我 setExecutor
我的 httpServer
这个问题会得到解决,但我开始在我的服务器端和客户端出现异常 (SOAP-UI ).我测试了各种执行器,包括 Executors.newCachedThreadPool
、 Executors.newFixedThreadPool
、Executors.newWorkStealingPool
、Executors.newScheduledThreadPool
没有任何运气。
正如我所说,当我从 setExecutor
到 null
时,我的代码工作正常,但在此配置中,我的代码按顺序处理请求。
我不知道该怎么办。这是我的代码:
public class HTTPListener {
private HttpServer httpServer;
private int port = 1253;
public void stop() {
if (httpServer != null) {
httpServer.stop(0);
httpServer = null;
}
}
public void startHTTPServer() {
try {
httpServer = HttpServer.create(new InetSocketAddress(1252), 100);
httpServer.setExecutor(null);
httpServer.createContext("/", new RequestHandler());
httpServer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
当我设置执行器时出现此错误
java.io.IOException: stream closed
at sun.net.httpserver.FixedLengthOutputStream.write(FixedLengthOutputStream.java:68)
at sun.net.httpserver.PlaceholderOutputStream.write(ExchangeImpl.java:444)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
at com.RequestHandler.sendResponse(RequestHandler.java:61)
at com..RequestHandler.handle(RequestHandler.java:18)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79)
at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:82)
at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:675)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79)
at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:645)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
这是我的 RequestHandler Class:
public class RequestHandler implements HttpHandler {
private HttpExchange sender;
@Override
public void handle(HttpExchange httpExchange) throws IOException {
this.sender = httpExchange;
try {
String request = readRequestBody();
sendResponse(200, "Hello World !");
} catch (Exception e) {
e.printStackTrace();
} finally {
this.sender.close();
}
}
private String readRequestBody() throws Exception {
try (InputStream isr = sender.getRequestBody()) {
byte[] buffer = new byte[isr.available()];
isr.read(buffer);
return Arrays.toString(buffer);
} catch (IOException ex) {
throw new Exception(ex.getMessage());
}
}
private void sendResponse(int httpResponseCode, String response) throws IOException {
OutputStream outputStream = null;
try {
sender.getResponseHeaders().set("Content-Type", "text/html; charset=UTF-8");
sender.sendResponseHeaders(httpResponseCode, response.length());
outputStream = sender.getResponseBody();
outputStream.write(response.getBytes());
} finally {
if (outputStream != null)
outputStream.close();
}
}
}
而且我在客户端也收到了这个错误代码
org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 13; received: 0
at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:180)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:137)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.Reader.read(Reader.java:140)
at org.apache.http.util.EntityUtils.toString(EntityUtils.java:247)
at org.apache.http.util.EntityUtils.toString(EntityUtils.java:291)
at Business.HTTPHandler.Client.send(Client.java:68)
at main.Main.lambda$main(Main.java:86)
at java.lang.Thread.run(Thread.java:745)
org.apache.http.client.ClientProtocolException
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
at Business.HTTPHandler.Client.send(Client.java:67)
at main.Main.lambda$main(Main.java:86)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.http.ProtocolException: Invalid header: *
at org.apache.http.impl.io.AbstractMessageParser.parseHeaders(AbstractMessageParser.java:232)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:268)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:165)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:272)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
... 5 more
Caused by: org.apache.http.ProtocolException: Invalid header: 13
at org.apache.http.impl.io.AbstractMessageParser.parseHeaders(AbstractMessageParser.java:232)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:268)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:165)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:272)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
... 5 more
你的 RequestHandler
class 不是线程安全的,这就是为什么它在你 运行 单线程时有效而在使用执行程序时失败的原因。
不要将HttpExchange
对象存储在sender
变量中。当所有线程都覆盖同一个变量时,它会导致竞争条件,并且可能看到处于错误状态的错误对象(例如,已经关闭流的对象)。
您可以将其作为参数传递给您的方法。你真的不需要额外的变量。
我在我的应用程序中使用 sun.net.httpServer
到 运行 HTTP 服务器(不要问我为什么)。
问题是它只在一个线程中处理我的请求,所以我的吞吐量是一场灾难。
我想如果我 setExecutor
我的 httpServer
这个问题会得到解决,但我开始在我的服务器端和客户端出现异常 (SOAP-UI ).我测试了各种执行器,包括 Executors.newCachedThreadPool
、 Executors.newFixedThreadPool
、Executors.newWorkStealingPool
、Executors.newScheduledThreadPool
没有任何运气。
正如我所说,当我从 setExecutor
到 null
时,我的代码工作正常,但在此配置中,我的代码按顺序处理请求。
我不知道该怎么办。这是我的代码:
public class HTTPListener {
private HttpServer httpServer;
private int port = 1253;
public void stop() {
if (httpServer != null) {
httpServer.stop(0);
httpServer = null;
}
}
public void startHTTPServer() {
try {
httpServer = HttpServer.create(new InetSocketAddress(1252), 100);
httpServer.setExecutor(null);
httpServer.createContext("/", new RequestHandler());
httpServer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
当我设置执行器时出现此错误
java.io.IOException: stream closed
at sun.net.httpserver.FixedLengthOutputStream.write(FixedLengthOutputStream.java:68)
at sun.net.httpserver.PlaceholderOutputStream.write(ExchangeImpl.java:444)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
at com.RequestHandler.sendResponse(RequestHandler.java:61)
at com..RequestHandler.handle(RequestHandler.java:18)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79)
at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:82)
at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:675)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79)
at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:645)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
这是我的 RequestHandler Class:
public class RequestHandler implements HttpHandler {
private HttpExchange sender;
@Override
public void handle(HttpExchange httpExchange) throws IOException {
this.sender = httpExchange;
try {
String request = readRequestBody();
sendResponse(200, "Hello World !");
} catch (Exception e) {
e.printStackTrace();
} finally {
this.sender.close();
}
}
private String readRequestBody() throws Exception {
try (InputStream isr = sender.getRequestBody()) {
byte[] buffer = new byte[isr.available()];
isr.read(buffer);
return Arrays.toString(buffer);
} catch (IOException ex) {
throw new Exception(ex.getMessage());
}
}
private void sendResponse(int httpResponseCode, String response) throws IOException {
OutputStream outputStream = null;
try {
sender.getResponseHeaders().set("Content-Type", "text/html; charset=UTF-8");
sender.sendResponseHeaders(httpResponseCode, response.length());
outputStream = sender.getResponseBody();
outputStream.write(response.getBytes());
} finally {
if (outputStream != null)
outputStream.close();
}
}
}
而且我在客户端也收到了这个错误代码
org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 13; received: 0
at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:180)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:137)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.Reader.read(Reader.java:140)
at org.apache.http.util.EntityUtils.toString(EntityUtils.java:247)
at org.apache.http.util.EntityUtils.toString(EntityUtils.java:291)
at Business.HTTPHandler.Client.send(Client.java:68)
at main.Main.lambda$main(Main.java:86)
at java.lang.Thread.run(Thread.java:745)
org.apache.http.client.ClientProtocolException
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
at Business.HTTPHandler.Client.send(Client.java:67)
at main.Main.lambda$main(Main.java:86)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.http.ProtocolException: Invalid header: *
at org.apache.http.impl.io.AbstractMessageParser.parseHeaders(AbstractMessageParser.java:232)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:268)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:165)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:272)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
... 5 more
Caused by: org.apache.http.ProtocolException: Invalid header: 13
at org.apache.http.impl.io.AbstractMessageParser.parseHeaders(AbstractMessageParser.java:232)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:268)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:165)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:272)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
... 5 more
你的 RequestHandler
class 不是线程安全的,这就是为什么它在你 运行 单线程时有效而在使用执行程序时失败的原因。
不要将HttpExchange
对象存储在sender
变量中。当所有线程都覆盖同一个变量时,它会导致竞争条件,并且可能看到处于错误状态的错误对象(例如,已经关闭流的对象)。
您可以将其作为参数传递给您的方法。你真的不需要额外的变量。