Netty Handler没有打电话

时间:2014-11-21 07:53:57

标签: java client-server netty

我正在尝试使用简单的服务器 - 客户端应用程序进入Netty(代码见下文)。

我正在努力解决两个问题:

  1. ConfigServerHandler和。正确调用ConfigClientHandler。但是FeedbackServerHandler分别是从不调用FeedbackClientHandler。为什么?根据文档,应该一个接一个地调用处理程序。

  2. 我想要几个处理程序。这些处理程序中的每一个仅对另一方发送的一些消息感兴趣(例如,由客户端发送,由服务器接收)。

    • 应该在处理程序(channelRead)收到消息后过滤消息吗?我如何区分不同的字符串?对于不同的对象,通过解析它们应该非常容易。
    • 是否可以为SocketChannel定义不同的ChannelPipelines?
    • 进一步接近?
  3. 感谢您的帮助!

    KJ

    这就是服务器的创建方式:

    public void run() 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) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     p.addLast(
                         new ObjectEncoder(),
                         new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
                         new ConfigServerHandler(),
                         new FeedbackServerHandler());
                 }
             });
          b.bind(mPort).sync().channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
    

    其中一个Handler类(FeedbackServerHandler完全相同但解析为Integer):

    public class ConfigServerHandler extends ChannelInboundHandlerAdapter {
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            System.out.println("ConfigServerHandler::channelRead, " +(String)msg);
            ctx.write(msg);
        }
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) {
            ctx.flush();
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
       }
    }
    

    客户端看起来很相似:

    public Client(String host, int port) throws InterruptedException {
    
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup)
             .channel(NioSocketChannel.class)
             .handler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                      p.addLast(
                          new ObjectEncoder(),
                          new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
                          new ConfigClientHandler(),
                          new FeedbackClientHandler());
                 }
             });
             b.connect(host, port).sync().channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
    

    这是一个客户端处理程序(另一个发送Integer消息并在'channelRead'方法中解析为Integer):

    public class ConfigClientHandler extends ChannelInboundHandlerAdapter {
    
        private final String firstMessage = "blubber";
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            System.out.println("ConfigClientHandler::channelActive");
            ctx.writeAndFlush(firstMessage);
        }
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            System.out.println("ConfigClientHandler::channelRead, " +(String)msg);
            ctx.write(msg);
        }
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) {
            ctx.flush();
        }
    

    }

1 个答案:

答案 0 :(得分:8)

您正在使用ChannelInboundHandlerAdapter,这对您的“中间”处理程序ConfigXxxxxHandler很好。

但您使用channelRead方法,然后在ctx.write(msg)内使用。 ctx.write(msg)将首先通过前一个处理程序(ObjectDecoder)将msg写回另一个服务器,而不是下一个处理程序(在您的情况下为FeedbackClientHandler)。

如果要将消息发送到下一个处理程序,则应使用以下内容:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    System.out.println("ConfigClientHandler::channelRead, " +(String)msg);
    ctx.fireChannelRead(msg);
}

当然ctx.flush()中没有channelReadComplete(因为不再写在那里)。 但是,在最后的FeedbackClientHandler中,请使用ctx.write(yourNewMessage)的flush方法或使用ctx.writeAndFlush(yourNewMessage)

所以要恢复:

  • ctx.write会将消息发送到电汇,所以前一个处理程序发送到通道然后发送到网络,所以出站方式
  • ctx.fireChannelRead会将消息发送到下一个处理程序(相反方式),因此入站方式

有关详细信息,请参阅http://netty.io/wiki/new-and-noteworthy-in-4.0.html#wiki-h4-16

你或许也应该反转编码器/解码器,因为一般来说最好首先是解码器,然后是管道中的编码器。

            p.addLast(
                      new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
                      new ObjectEncoder(),
                      new ConfigClientHandler(),
                      new FeedbackClientHandler());