翻译

原文 stackoverflow

让我们假设在 pipeline 里有三个 handlers , 它们都都拦截 close() 方法操作, 并且在面里调用 ctx.close()

ChannelPipeline p = ...;
p.addLast("A", new SomeHandler());
p.addLast("B", new SomeHandler());
p.addLast("C", new SomeHandler());
...

public class SomeHandler extends ChannelOutboundHandlerAdapter {
    @Override
    public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
        ctx.close(promise);
    }
}
  • Channel.close() 会触发 C.close() , B.close(), A.clos(), 然后再关闭 channel
  • ChannelPipeline.context("C").close() 会触发 B.close(), A.close(), 然后再关闭 channel
  • ChannelPipeline.context("B").close() 会触发 A.close(), 然后再关闭 channel
  • ChannelPipeline.context("A").close() 则会直接关闭 channel. 不再会有 handlers 调用了.

因此, 什么时候应该使用 Channel.close()ChannelHandlerContext.close() ? 最好规则如下:

  • 如果你正写一个 ChannelHandler, 并且想在这个 handler 中关闭 channel, 则调用 ctx.close()
  • 如果你正准备从一个外部的 handler (例如, 你有一个后台的非I/O线程, 并且你想从该线程中关闭连接). (译注: 这时是调用 Channel.close() ?)

总结

是不是, 整条流水线上, 如果后面的 handler 不用关心 close() 事件的话, 则用 ctx.close(), 否则用 channel.close().

就像官方文档中对 pipeline 的描述那样, ctx.write() 是从当前的 handler 中, 写到离它最近的 out handler 中, 而不是从流水线最后开始从头穿过处理一样~

官方关于流水线的文档: doc

新手容易引起的流水线问题

pipeline 中的顺序是非常重要的~比如, 有个程序这样子初始化 pipeline:

    @Override
    protected void initChannel(final Channel ch) {
        ChannelPipeline p = ch.pipeline();
        p.addLast(new HttpRequestDecoder());
        p.addLast(new HttpResponseEncoder());
        p.addLast(new InHandler1());
        p.addLast(new InHandler2());
        p.addLast(new OutHandler1());
        p.addLast(new OutHandler2());
    }

如果在 InHandler2 中, 调用了 write(...) 则不会触发调用 OutHandler2OutHandler1 的, 因为 ctx.write(...) 只会触发离它最近的 out handler, 但是, InHandler2 前面没有 out handler了~

但, 如果通过 channel.write(...)的话, 则它会从 OutHandler2 -> OutHandler1 这样子流穿.

其实其他的事件, 也同理~