我正在尝试创建一个简单的异步Netty HTTP服务器。我需要支持的关键特性是能够将事件中包含的HttpRequest发送到事件驱动的组件(在同一个JVM中),该组件将处理事件并生成响应。此事件驱动的组件在与Netty组件的单独线程中运行。
我已经按照一些例子来构建适合我的东西,以及当我在与处理程序相同的线程中生成响应时我的工作原理
我编写/改编的自定义处理程序是:
private class WebServerHandler extends SimpleChannelInboundHandler<Object> {
String uri;
@Override
public void messageReceived(final ChannelHandlerContext ctx, final Object msg) {
if (!(msg instanceof FullHttpRequest)) return;
final FullHttpRequest request = (FullHttpRequest) msg;
uri = request.uri();
System.out.println("Handling: " + uri);
if (HttpUtil.is100ContinueExpected(request)) send100Continue(ctx);
final Handler handler = WebServer.this.getHandler(request.uri());
if (handler == null) {
writeNotFound(ctx, request);
} else {
try {
handler.handle(ctx, request);
} catch (final Throwable ex) {
ex.printStackTrace();
writeInternalServerError(ctx, request);
}
}
}
@Override
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
ctx.close();
}
@Override
public void channelReadComplete(final ChannelHandlerContext ctx) {
System.out.println("Completed: " + uri);
// ctx.flush();
}
}
当我将事件发送到事件驱动的组件(它再次在单独的线程中运行)时,会出现问题。在这种情况下,在事件驱动的组件处理事件之前调用上述channelReadComplete(...)
方法。在我用来测试解决方案的Web浏览器中,连接永远不会终止。
我正在使用的管道是:
final ChannelPipeline p = ch.pipeline();
p.addLast("decoder", new HttpRequestDecoder(4096, 8192, 8192, false));
p.addLast("aggregator", new HttpObjectAggregator(100 * 1024 * 1024));
p.addLast("encoder", new HttpResponseEncoder());
p.addLast("handler", new WebServerHandler());
我没有包含事件驱动组件的任何信息,因为它是一个庞大而复杂的系统(它实际上是一种编程语言),但我知道相关代码正在被成功调用。我试图执行以生成响应的实际代码是:
File file = new File(file_uri);
System.out.println("file: " + file.getAbsolutePath());
RandomAccessFile raf = new RandomAccessFile(file, "r");
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
HttpUtil.setContentLength(response, raf.length());
ctx.write(response);
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, file.length()));
ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
raf.close();
所以,我的问题是 - 在我发送响应之前,如何阻止Netty调用channelReadComplete(...)
方法?
答案 0 :(得分:1)
我认为你的raf.close
调用应该在一个附加到你文件写入的监听器中。正如所写,我希望你在写电话有机会阅读之前关闭文件。您的响应正确设置了内容长度,但如果您不写那么多字节,因为您提前关闭文件,那么您的客户端将等待其余的。
您应该在管道中的聚合器之前移动编码器。聚合器可以发送编码器需要编码的响应。请查看使用HttpServerCodec,因为它可以用一个处理程序替换您的编码器/解码器。
您使用Object作为类型扩展 SimpleChannelInboundHandler ,但随后拒绝除 FullHttpRequest 消息之外的任何内容。如果您更改了扩展中的类型,那么the parent class will take care of that check and casting for you(您使用的是Netty 5吗?为什么?)。
示例:
... extends SimpleChannelInboundHandler<FullHttpRequest> {
...
public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) {
我不认为channelReadComplete
被称为早期事务。由于您已经在读取/响应处理程序中刷新,因此channelReadComplete
中的刷新是不必要的。