繁体   English   中英

netty 中的解码器、编码器、ServerHandler 管道

[英]Decoder, Encoder, ServerHandler pipeline in netty

查看文档,它说:

https://netty.io/4.0/api/io/netty/channel/ChannelPipeline.html

用户应该在管道中有一个或多个 ChannelHandler 来接收 I/O 事件(例如读取)和请求 I/O 操作(例如写入和关闭)。 例如,典型的服务器将在每个通道的管道中具有以下处理程序,但您的里程可能会因协议和业务逻辑的复杂性和特征而异:

协议解码器 - 将二进制数据(例如 ByteBuf)转换为 Java 对象。 协议编码器 - 将 Java 对象转换为二进制数据。

业务逻辑处理程序 - 执行实际的业务逻辑(例如数据库访问)。 它可以表示为如下示例所示: static final EventExecutorGroup group = new DefaultEventExecutorGroup(16); ...

ChannelPipeline 管道 = ch.pipeline();

pipeline.addLast("decoder", new MyProtocolDecoder());

pipeline.addLast("encoder", new MyProtocolEncoder());

// 告诉管道在与 I/O 线程不同的线程中 // 运行 MyBusinessLogicHandler 的事件处理程序方法,以便 I/O 线程不会被耗时的任务阻塞 //。 // 如果您的业务逻辑是完全异步的或很快完成,您就不需要 // 指定一个组。

pipeline.addLast(group, "handler", new MyBusinessLogicHandler());

在 Github 上的许多示例中,我看到了相同的模式。 我想知道是否有人可以解释为什么 businessHandler 不在解码器和编码器之间。 我认为你会得到你的 POJO,然后在业务处理程序中处理它,然后对它进行编码。

由于调用处理程序的顺序,解码器和编码器通常位于管道的开头。 对于传入的数据,它是自下而上的,而传出的数据是自上而下的。

例如

pipeline.addLast(new MyEncoder());
pipeline.addLast(new MyDecoder());
pipeline.addLast(new MyBusiness());

在这种情况下,传入数据的调用顺序是:MyDecoder(将数据转换为POJO)-> MyBusiness(传入流不调用编码器),传出数据:MyBusiness -> MyEncoder(传出流不调用解码器) .

如果您在业务处理程序(实际上是解码器之后的 POJO)中接收到传入流并将其写回,则看起来 MyBusiness 位于编码器和解码器之间,因为数据正在返回编码器。

当然,业务处理程序介于解码器和编码器之间。以 Factorial 示例为例。

   public void initChannel(SocketChannel ch) {
    ChannelPipeline pipeline = ch.pipeline();
    if (sslCtx != null) {
        pipeline.addLast(sslCtx.newHandler(ch.alloc()));
    }
    // Enable stream compression (you can remove these two if unnecessary)
    pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
    pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
    // Add the number codec first,
    pipeline.addLast(new BigIntegerDecoder());
    pipeline.addLast(new NumberEncoder());
    // and then business logic.
    // Please note we create a handler for every new channel
    // because it has stateful properties.
    pipeline.addLast(new FactorialServerHandler());
}`

initChannel的函数中initChannel pipeline先添加encoder和decoder,最后添加handler。 执行流程实际上是按解码器、处理程序和编码器排序的。 解码器、处理程序和编码器等处理程序实际上存储在AbstractChannelHandlerContext类中。 Netty 中有一个AbstractChannelHandlerContext的链表。 列表的排列方式是decoder context --> handler context --> encoder context ,执行是一样的!

事实上,如果你在你的服务器中添加ctx.channel().writeAndFlush() ,并且你编写ctx.channel().writeAndFlush()ctx.pipeline().writeAndFlush() ,那么编码器将被调用. 在这种情况下是 bc,它将从尾部开始寻找上一个 outboundChannel。 但是,如果您编写ctx.writeAndFlush() ,它将从 businessHandler 的位置查找上一个 outboundChannel。 在AbstractChannelHandlerContext的findContextOutbound()的第一行加断点,就搞定了。

private AbstractChannelHandlerContext findContextOutbound(int mask) {
        AbstractChannelHandlerContext ctx = this;
        EventExecutor currentExecutor = executor();
        do {
            ctx = ctx.prev;
        } while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_OUTBOUND));
        return ctx;
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM