尝试在Netty中检索最后一个处理程序时,间歇性地使处理程序上为Null

时间:2019-06-01 06:39:42

标签: netty

我有一个Netty客户端,该客户端连接到远程服务器以进行请求-响应。我想阻止直到远程连接成功并解析响应。我的处理程序在检索结果方面类似于Netty factorial example

这就是我所拥有的

Channel ch = bootstrap.connect(addr).sync().channel();
ChannelFuture f = ch.writeAndFlush(obj);
//blocking operation
ch.closeFuture().sync();
MyHandler handler = (MyHandler) f.channel().pipeline().last(); //this handler is null
String responseString = handler.responseString;
f.channel().close();

处理程序代码

MyHandler extends ChannelInboundHandlerAdapter {

     public String result = null;
       @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof FullHttpResponse) {
            result = parse(msg);
         }
        // The following line automatically closes the channel: 

ctx.channel().writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        }
    }

为什么处理程序会间歇性地使null无效,正确的处理方式是什么? (我在抛出NPE的行上发表了评论)

1 个答案:

答案 0 :(得分:2)

您需要了解的一件事是,当Netty通道处于关闭状态时,最后一步是它将所有处理程序删除,因此需要执行此步骤,因此所有清理例程都将在其中运行处理程序。

这意味着,在关闭通道之后,您将无法访问管道中的任何处理程序。

在您的代码中,您正在等待通道完全关闭的事件,这意味着之后的代码与通道关闭事件具有“后发生”关系。

一个解决方案是制作一个自定义的Promise对象,并将其传递给处理程序,然后由处理程序填充响应:

// Somewhere inside the application:
public static final AttributeKey<Promise<String>> RESPONSE = new AttributeKey("RESPONSE");

ChannelFuture chf = bootstrap.connect(addr);
Promise<String> p = chf.channel().eventLoop().newPromise();
chf.channel().attr(RESPONSE).set(p);
//blocking operation
Channel ch = chf.sync().channel();
ChannelFuture f = ch.writeAndFlush(obj);
//blocking operation
String responseString = p.get();
f.channel().close();

....

// Inside you handler

MyHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof FullHttpResponse) {
            ctx.channel().attr(RESPONSE).get().setSuccess(parse(msg));
        }
        // The following line automatically closes the channel: 
        ctx.channel()
            .writeAndFlush(Unpooled.EMPTY_BUFFER)
            .addListener(ChannelFutureListener.CLOSE);
    }
}

此解决方案有效,因为即使在选择时清除了通道及其属性,我们仍然可以引用包含最终结果的承诺