Netty Outbound Handler没有被调用

时间:2016-09-01 20:51:43

标签: netty

我正在使用Netty 4.1.0.Final,我遇到的问题是消息没有通过出站处理程序。我发布了一个示例程序,其中有一个入站和一个出站处理程序。入站处理程序在ChannelHandlerContext中使用writeAndFlush,我的理解是它应该将消息转发到管道中可用的第一个可用的出站处理程序。为简单起见,忽略内存管理。

Bootstrap Code

EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .localAddress(12021)
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 protected void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new TestHandler1(), new TestOutHandler1());
                 }
             });
ChannelFuture future = bootstrap.bind().sync();
System.out.println("Server Started...");
    future.channel().closeFuture().sync();
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
    System.out.println("Server Shutdown");

入站处理程序代码

public class TestHandler1 extends ChannelInboundHandlerAdapter {


private static Log logger = LogFactory.getLog(TestHandler1.class);

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    logger.info("channelRead");
    ctx.writeAndFlush(msg);
}

}

出站处理程序代码

public class TestOutHandler1 extends ChannelOutboundHandlerAdapter {

private static Log logger = LogFactory.getLog(TestOutHandler1.class);

@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    logger.info("write");
    ctx.writeAndFlush(msg);
}

}

输出

  

INFO TestHandler1:channelRead

如果我通过在通道而不是ChannelHandlerContext上执行writeAndFlush()来更改我的Inbound Handler,我得到了预期的输出

经过修改的入境Hanndler

public class TestHandler1 extends ChannelInboundHandlerAdapter {

private static Log logger = LogFactory.getLog(TestHandler1.class);

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    logger.info("channelRead");
    ctx.channel().writeAndFlush(msg);
}

}

输出

  

INFO TestHandler1:channelRead

     

INFO TestOutHandler1:写

根据诺曼在下面链接中的解释,我理解为ChannelHandlerContext.write(...)应该通过它前面的ChannelOutboundHandlers,在我的情况下是唯一的出站处理程序。

Norman's Explanation

如果我的理解错误或者我遗漏了什么,请告诉我。

3 个答案:

答案 0 :(得分:3)

因为您在ChannelOutboundHandler ChannelInboundHandler之前添加ChannelPipeline. ChannelHandlerContext.writeAndFlush(...) ChannelPipeline将从ChannelHandler ChannelOutboundHandler处的uniq点开始} 被添加。因此,在require 'mongo' require 'bson' Mongo::Logger.logger.level = ::Logger::FATAL puts "Working..." db = Mongo::Client.new([ 'localhost:27017' ], :database => 'supers') coll = db[:hashes] # suppressors = File.open('_combined.txt') suppressors = Dir['./_uniqued_*.txt'] count = suppressors.count puts "Found #{count}" suppressors.each_with_index do |fileroute, i| suppressor = File.open(fileroute, 'r') percentage = ((i+1) / count.to_f * 100).round(2) puts "Working on `#{fileroute}` (#{i+1}/#{count} - #{percentage})" c = 0 suppressor.each_line do |hash| c+=1 coll.update_one({ :_id => hash }, { :$inc => { :count => 1 } }, { upsert: true} ) puts "Processed 50k records for #{fileroute}" if c % 50_000 == 0 end end 按预期工作之前添加$inc

答案 1 :(得分:1)

以前的答案很好,我想解释这个问题的另一个方面:     通过调用ctx.writeAndFlush()ctx.channel.writeAndFlush()

得到不同的结果

Structure of your Channel

  1. ctx.writeAndFlush()
    在当前ctx之前找到第一个OutboundHandler。在您的频道中,找不到任何内容。因此只打印一个信息。
  2. ctx.channel.writeAndFlush()
    实际上,ctx.channel.writeAndFlush()将调用pipeline.tail.writeAndFlush()。这等于在您频道的尾部ctx上调用writeAndFlush()。这样,将找到TestOutHandler1并调用TestOutHandler1.write()。然后打印两个信息。

答案 2 :(得分:0)

根据源代码,无论添加处理程序的类型(入站还是出站),每个处理程序都链接在一个管道中。每当处理程序调用相应的ChannelHandlerContext的write方法时,消息将是传递给OutboundHandler类型的前一个最近的处理程序。请参考下面的源代码:

private AbstractChannelHandlerContext findContextOutbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.prev;
        } while (!ctx.outbound);
        return ctx;
    }

消息只会在它之前发送到OutboundHandler。因此,如果要将消息传递给OutboundHandler,首先应该添加OutboundHandler,确保在InboundHandler之前添加OutboundHandler,然后OutboundHandler将得到消息。