2014-11-21 96 views
5

我想使用一個簡單的服務器客戶端應用程序進入Netty(代碼見下文)。Netty處理程序不叫

我有兩個問題掙扎:

  1. 的ConfigServerHandler RESP。正確調用ConfigClientHandler。但是FeedbackServerHandler響應。 FeedbackClientHandler永遠不會被調用。爲什麼?根據文檔,處理程序應該被一個接一個地調用。

  2. 我想有幾個處理程序。這些處理程序中的每一個僅僅對另一方發送的一些消息感興趣(例如,由客戶端發送,由服務器接收)。

    • 我應該在處理程序(channelRead)收到消息後過濾消息嗎?我怎樣才能區分不同的字符串?用不同的對象解析它們應該很容易。
    • 是否可以爲SocketChannel定義不同的ChannelPipelines?
    • 更進一步的方法?

感謝您的幫助!

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

一個處理程序類(在FeedbackServerHandler不完全一樣,但解析成整數):

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

這裏是客戶端處理程序之一(另一個發送一個整數消息,並解析成整數的「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(); 
    } 

}您使用ChannelInboundHandlerAdapter

回答

5

,這很好,爲您的「中間」處理程序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()(因爲沒有更多的寫有)。 但在您的最終FeedbackClientHandler,當然,使用沖洗方法與ctx.write(yourNewMessage)或使用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());