【问题标题】:Decoder, Encoder, ServerHandler pipeline in nettynetty 中的解码器、编码器、ServerHandler 管道
【发布时间】:2017-10-19 02:12:34
【问题描述】:

查看文档,它是这样说的:

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

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

Protocol Decoder - 将二进制数据(例如 ByteBuf)翻译成 Java 目的。 协议编码器 - 将 Java 对象转换为二进制数据。

Business Logic Handler - 执行实际的业务逻辑(例如 数据库访问)。它可以表示为 以下示例:静态最终 EventExecutorGroup 组 = 新 DefaultEventExecutorGroup(16); ...

ChannelPipeline 管道 = ch.pipeline();

pipeline.addLast("解码器", new MyProtocolDecoder());

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

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

pipeline.addLast(group, "handler", 新的 MyBusinessLogicHandler());

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

【问题讨论】:

    标签: java netty


    【解决方案1】:

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

    例如

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

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

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

    【讨论】:

      【解决方案2】:

      当然业务处理器是在解码器和编码器之间。以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());
      }`
      

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

      【讨论】:

        【解决方案3】:

        实际上,如果你在你的服务器中添加1.decoder,2.businessHandler,3.encoder,然后你写ctx.channel().writeAndFlush()或者ctx.pipeline().writeAndFlush(),那么就会调用encoder。在这种情况下是 bc,它会从尾部开始寻找 prev outboundChannel。但是,如果你写ctx.writeAndFlush(),它会从businessHandler的位置寻找prev 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;
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-12
          • 1970-01-01
          • 2017-11-20
          • 1970-01-01
          • 2023-03-25
          • 2018-04-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多