什么是netty中的channelhandler序列?

时间:2014-11-18 15:10:55

标签: java netty

我有一个使用netty来实现服务器和客户端的应用程序。服务器端将当前时间发送到客户端。

public class TimeServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("in timeserverhandler");
        ChannelFuture f = ctx.writeAndFlush(new UnixTime());
        f.addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

编码器:

  public class TimeEncoder extends ChannelOutboundHandlerAdapter {
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        System.out.println("in timeencoder");
        UnixTime m = (UnixTime) msg;
        ByteBuf encoded = ctx.alloc().buffer(4);
        encoded.writeInt(m.value());
        ctx.write(encoded, promise); // (1)
    }


}
  

公共类TimeServer {       private static final int PORT = 9000;

public static void main(String[] args) throws Exception {
    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    try {
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) {
                        ChannelPipeline p = ch.pipeline();
                        p.addLast(new TimeEncoder(), new TimeServerHandler());
                       //p.addLast(new TimeServerHandler(), new TimeEncoder());

                    }
                });
        ChannelFuture f = b.bind(PORT).sync();
        f.channel().closeFuture().sync();
    } finally {
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }

}
     

}

在TimeServer中,如果我将addList sequnce更改为注释行,则永远不会调用编码器处理程序,并且客户端无法打印出当前时间。为什么这样,以及管道中处理程序的执行顺序是什么?

4 个答案:

答案 0 :(得分:2)

佩德罗是对的。

您通常可以插入第一个解码器,然后插入编码器,最后插入应用程序处理程序。

通常逻辑是:解码器后跟编码器

如果您有多个编解码器逻辑(例如,第一个编解码器后面必须跟第二个编解码器,中间有一个处理程序),那么逻辑将是:

  • pipeline.addLast(decoderProtocol1, encoderProtocol1)最后是.addLast(intermediaryHandler1)
  • pipeline.addLast(decoderProtocol2, encoderProtocol2)最后是.addLast(intermediaryHandler2)
  • ...
  • pipeline.addLast(decoderProtocoln, encoderProtocoln)
  • pipeline.addLast(finalHandler)

某些解码器/编码器也带有一个处理程序,作为编解码器,显然您只需将pipeline.addLast(decoderProtocoln, encoderProtocoln)替换为pipeline.addLast(codecProtocoln)

文档的正确链接是: http://netty.io/4.0/api/io/netty/channel/ChannelPipeline.html

答案 1 :(得分:0)

在创建管道时,我总是把&#34; addLast(解码器,编码器,处理程序)&#34;。

检查一下:{&3 34}&#34;建立管道&#34;部分。

答案 2 :(得分:0)

这是因为你使用ChannelHandlerContext.write而不是Channel.write。 http://netty.io/4.0/api/io/netty/channel/ChannelPipeline.html声明ChannelHandlerContext方法将事件转发到管道中的下一个处理程序(上游或下游,具体取决于事件类型),而不是从管道的开始。在您的代码中,管道是

  • 网络
  • TimeEncoder
  • TimeServerHandler

这很好,但注释的代码是

  • 网络
  • TimeServerHandler
  • TimeEncoder

尝试直接写回网络,因为TimeEncoder是TimeServerHandler的上游。

答案 3 :(得分:0)

简短回答:您的注释行不起作用的原因是netty不了解java对象(UnixTime())。它只能理解二进制数据(ByteBuf)。

说明:现在,处理程序执行的顺序取决于您在管道中添加它们的顺序。对于入站数据,处理程序从头到尾执行。对于出站数据,处理程序从最后到第一个执行。现在,在处理程序执行期间,netty会检查您的处理程序是否能够处理入站/出站数据。这是通过检查您的处理程序是否扩展ChannelInboundHandlerAdapter或/和ChannelOutboundHandlerAdapter来完成的。如果它扩展了ChannelInboundHandlerAdapter,则对入站数据执行相同的操作。或者,如果扩展ChannelOutboundHandlerAdapter,它将针对出站数据执行。

现在,在工作代码中,您的第一个处理程序是编码器(处理出站事件),第二个处理程序是编写java对象(处理入站事件)。在这种情况下,每当通道变为活动状态时,将生成入站事件,并将相同的内容传递给管道中的第一个处理程序,这是您的最后一个处理程序。现在,该处理程序将使用事件并在作为出站事件的通道上写入数据。现在,这个出站甚至将传播到上游并转到管道中的下一个处理程序,该处理程序处理作为编码器的出站事件。现在,编码器将unixtime转换为二进制数据,同样将传递到通道。

现在,在非工作代码中,当您反转处理程序的顺序时,一旦通道变为活动状态,入站事件将被传递给您的第一个出站事件处理程序,这是管道中的最后一个处理程序(从开始但是从最后一个开始结束 )。一旦此处理程序生成unix时间,它将生成将进一步向上游传播的出站事件。但在此之后,没有上游事件处理程序来消耗出站事件,因此你的unix时间永远不会被转换为二进制数据,因此这不起作用。

希望它澄清。