【问题标题】:How Netty ChannelFuture works?Netty ChannelFuture 是如何工作的?
【发布时间】:2017-01-09 05:04:47
【问题描述】:

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

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

  1. 客户端发送请求 -> 服务器(netty)
  2. 服务器使用 ctx.writeAndFlush(msg); 发送响应
  3. 在第 2 步完成后,服务器会向该 ctx 发送更多消息。

问题是,如果我这样做,第二次写入将不会发送出去:

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有什么潜在的问题吗?

【问题讨论】:

    标签: java netty future


    【解决方案1】:

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

    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 并不意味着它成功的情况。

    【讨论】:

      【解决方案2】:

      试试这个:

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

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

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          最近更新 更多