我正在使用java.nio
创建一个小型服务器,但在尝试对其进行压力测试时,我不断收到有关在服务器端重置连接的消息,或者更具体地说:
apr_socket_recv: An established connection was aborted by the software in your host machine
我试图将其缩小到最简单的循环,但仍然没有运气。我可以在一百个左右的连接之后得到错误,或者可能只是在1或2之后。
这是服务器循环:
byte[] response = ("HTTP/1.1 200 OK\r\n"
+ "Server: TestServer\r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n"
+ "<html><b>Hello</b></html>").getBytes();
SocketChannel newChannel = null;
while (active) {
try {
//get a new connection and delegate it.
System.out.print("Waiting for connection..");
newChannel = serverSocketChannel.accept();
System.out.println("ok");
newChannel.configureBlocking(true);
newChannel.write(ByteBuffer.wrap(response));
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
newChannel.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
我已经尝试检查写入是否没有写入所有请求的字节,但看起来确实如此。有趣的是,在每个System.gc()
之后调用newChannel.close()
会使问题消失(但作为回报,它的速度非常慢)。所以要么我不释放我应该发布的所有资源,要么应用程序只需要暂停..
我在这方面失去了所有最好的岁月。哦,顺便说一句..如果我忽略写入通道并在接受连接后关闭,问题仍然不会消失。
答案 0 :(得分:0)
我发现了它,所以我不妨分享它。
我的应用需要暂停。它只是过快,并在客户端编写了所有请求数据之前关闭了连接。修复将继续阅读,直到收到整个HTTP请求。噢噢......上课了。
答案 1 :(得分:0)
来自the docs for SocketChannel#Write(强调我的):
尝试将 r 字节写入通道,其中 r 是 缓冲区中剩余的字节数,即
src.remaining()
, 此时调用此方法。[...]
返回: 写入的字节数,可能为零 。
由您来检查写入调用的返回值(您当前没有这样做),并发出连续的写入调用,直到整个缓冲区已被发送。我想是这样的事情:
ByteBuffer toWrite = ByteBuffer.wrap(response);
while (toWrite.remaining() > 0) {
newChannel.write(toWrite);
}
如果您没有写完所有的响应数据然后关闭套接字,那么您很明显会中止。