2014-11-21 19 views
5

Sto cercando di entrare in Netty usando una semplice applicazione client-server (codice vedi sotto).Netty Handler non chiamato

sto lottando con due problemi:

  1. il resp ConfigServerHandler. ConfigClientHandler è chiamato correttamente. Ma il FeedbackServerHandler risp. FeedbackClientHandler non viene mai chiamato. Perché? Secondo la documentazione, gli Handler dovrebbero essere chiamati uno dopo l'altro.

  2. Mi piacerebbe avere più gestori. Ognuno di questi gestori è interessato solo ad alcuni dei messaggi che vengono inviati dall'altro lato (ad esempio, invia dal client, ricevuto dal server).

    • devo filtrare i messaggi dopo che sono stati ricevuti da un gestore (channelRead)? Come posso distinguere le diverse stringhe? Con oggetti diversi questo dovrebbe essere abbastanza semplice analizzandoli.
    • è possibile definire diverse ChannelPipelines per un SocketChannel?
    • ulteriori approcci?

Grazie per il vostro aiuto!

KJ

questo modo si crea il server:

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(); 
    } 
} 

Una delle classi Handler (la FeedbackServerHandler fa esattamente lo stesso, ma analizza in 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(); 
    } 
} 

Il lato client sembra abbastanza simile:

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(); 
    } 
} 

E qui è uno dei gestori di lato client (l'altro invia un messaggio di Integer e analizza in Integer nel metodo 'channelRead'):

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(); 
    } 

}

risposta

5

Stai usando ChannelInboundHandlerAdapter, che va bene, per il tuo gestore "medio" ConfigXxxxxHandler.

Ma si utilizza il metodo channelRead e quindi utilizzare all'interno di ctx.write(msg). ctx.write(msg) scriverà nuovamente il msg all'altro server tramite il gestore precedente (ObjectDecoder), non al gestore successivo (FeedbackClientHandler nel tuo caso).

si dovrebbe utilizzare il seguente se si desidera inviare il messaggio al successivo gestore:

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

E naturalmente non ctx.flush() a (da non più scrivere lì). Ma nel tuo finale FeedbackClientHandler, ovviamente, usa il metodo flush con ctx.write(yourNewMessage) o usa ctx.writeAndFlush(yourNewMessage).

Quindi, per riprendere:

  • ctx.write invierà il messaggio al filo, quindi al gestore precedente verso il basso per il canale poi alla rete, in modo uscita modo
  • ctx.fireChannelRead invierà il messaggio al gestore successivo (in senso opposto), in modo Inbound modo

Vedi http://netty.io/wiki/new-and-noteworthy-in-4.0.html#wiki-h4-16 per i dettagli .

Forse dovresti anche invertire l'Encoder/Decoder, poiché in generale è consigliabile avere prima il decoder, quindi l'encoder nella pipeline.

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