Netty ChannelFuture如何运作?

时间:2016-09-01 10:42:16

标签: java netty future

我已阅读Netty Guide,但对ChannelFuture的解释并不多。我发现在应用它时,ChannelFuture是一个复杂的想法。

我要做的是在初始响应之后将消息写入上下文。与典型的请求/响应流程不同。我需要这样的流程:

  1. 客户端发送请求 - >服务器(网络)
  2. 服务器使用ctx.writeAndFlush(msg);
  3. 发送响应
  4. 服务器在第2步完成后向该ctx发送更多消息。
  5. 问题是,如果我这样做,第二次写不会发出:

    ctx.writeAndFlush(response);
    Message newMsg = createMessage();
    ctx.writeAndFlush(newMsg);   //will not send to client
    

    然后我尝试使用ChannelFuture,它有效,但我不确定我的逻辑是否正确:

    ChannelFuture msgIsSent = ctx.writeAndFlush(response);
    if(msgIsSent.isDone())
    {
        Message newMsg = createMessage();
        ctx.writeAndFlush(newMsg);   //this works
    }
    

    或者我应该使用ChannelFutureListener()吗?

    ChannelFuture msgIsSent = ctx.writeAndFlush(response);
    msgIsSent.addListener(new ChannelFutureListener(){
    @Override
    public void operationComplete(ChannelFuture future)
        {
           Message newMsg = createMessage();
           ctx.writeAndFlush(newMsg);
        }
    });
    

    这也有效吗?

    哪一种是最佳做法?使用方法2是否存在任何潜在问题?

3 个答案:

答案 0 :(得分:2)

当然,这也取决于您的“协议”(例如,如果您使用HTTP,则HTTP协议不支持为同一请求发送2个a​​nswears)。但是,假设您的协议允许您发送多个响应部分:

Netty添加要发送到管道的消息,尊重订单。

所以在你的第一个例子中,我有点惊讶它不起作用:

ctx.writeAndFlush(response);
Message newMsg = createMessage();
ctx.writeAndFlush(newMsg); // should send the message

然而,它可能会由您的协议引导。例如,这可能发生:

response in message queue to send
flush not yet done
newMsg in message queue to send
flush now come but protocol does not support 2 messages so only send first one

因此,如果您的协议必须承认已经发送了第一条消息,那么您必须等待第一条消息,所以执行以下操作:

ctx.writeAndFlush(response).addListener(new ChannelFutureListener() {
  @Override
  public void operationComplete(ChannelFuture future) {
    if (future.isDone()) {
      Message newMsg = createMessage();
      ctx.writeAndFlush(newMsg);
    } else { // an error occurs, do perhaps something else
    }
  }
});

所以你的最后一个提议(我只是不创建一个ChannelFuture但直接使用了writeAndFlush的结果,但两者都是等于)。只需注意operationComplete并不意味着它成功的情况。

答案 1 :(得分:0)

试试这个:

    ctx.channel().writeAndFlush(response);
    Message newMsg = createMessage();
    ctx.channel().writeAndFlush(newMsg);

Channel.write(..)始终从ChannelPipeline的尾部开始。

ChannelHandlerContext.write(...)从ChannelHandler的当前位置开始。

答案 2 :(得分:-1)

#2看起来更好,但一定要测试操作是否成功。如果没有,请使用future.getCause()来访问异常。并不是说它会改变功能,但你可以通过简单地直接在写调用的结果上添加监听器来缩短代码,即。你不需要宣布未来,因为它将在回调中提供。