периодически получать Null для обработчика при попытке получить последний обработчик в Netty - PullRequest
0 голосов
/ 01 июня 2019

У меня нетти-клиент, который подключается к удаленному серверу для запроса-ответа. Я хочу заблокировать, пока удаленное соединение не будет успешным, и проанализировать ответ. Мой обработчик похож на Netty factorial в получении результатов.

Вот что у меня есть

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);
        }
    }

почему обработчик периодически обнуляется и как правильно это сделать? (Я прокомментировал строку, где выбрасывается NPE)

1 Ответ

2 голосов
/ 01 июня 2019

Одна из вещей, о которых вам нужно знать, это то, что когда канал Netty находится в процессе закрытия, последний шаг - удаление всех обработчиков, этот шаг необходим, чтобы все процедуры очистки запускались внутри этих обработчики.

Это означает, что после закрытия канала вы не сможете получить доступ ни к одному из обработчиков в конвейере.

Внутри вашего кода вы ожидаете события, когда канал полностью закрылся, это означает, что код впоследствии имеет отношение «происходит после» к событию закрытия канала.

Одним из решений этого является создание объекта пользовательского обещания и передача его обработчику, который затем заполняет его ответом:

// 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);
    }
}

Это решение работает, потому что, хотя канал и его атрибуты очищаются при выборе, у нас все еще есть ссылка на обещание, которое содержит конечный результат

...