2013-08-30 17 views
0

我有以下情況:的Netty:channel.write掛在斷開

一個新的通道連接以這種方式打開:

ClientBootstrap bootstrap = new ClientBootstrap(
      new OioClientSocketChannelFactory(Executors.newCachedThreadPool())); 

    icapClientChannelPipeline = new ICAPClientChannelPipeline();   
    bootstrap.setPipelineFactory(icapClientChannelPipeline); 
    ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); 
    channel = future.awaitUninterruptibly().getChannel(); 

這是按預期工作。

東西被寫入通過以下方式聲道:

channel.write(chunk) 

這也按預期工作時與服務器的連接仍然活着。但是,如果服務器停機(機器脫機),則該調用將掛起並且不會返回。

我通過在channel.write(chunk)之前和之後添加日誌語句證實了這一點。連接中斷時,僅顯示以前的日誌語句。

  1. 這是什麼原因造成的?我認爲這些調用都是異步並立即返回?我也嘗試過與NioClientSocketChannelFactory相同的行爲。

  2. 我試圖用channel.getCloseFuture()但聽者不會被調用,我試着用channel.isOpen()channel.isConnected()channel.isWritable()寫前檢查通道,他們總是真的...

  3. 如何解決此問題?沒有異常拋出,沒有真正發生......一些問題如this onethis one表明無法檢測到沒有心跳的通道斷開連接。但是我無法實現心跳,因爲我無法更改服務器端。

環境:Netty的3,JDK 1.7

回答

0

好吧,我解決我自己上週這一個,所以我將添加答案completness。

我在3中錯了,因爲我想我不得不改變客戶端和服務器端的心跳。如in this question所述,您可以使用IdleStateAwareHandler來實現此目的。我實現這樣的:

的IdleStateAwareHandler:

public class IdleStateAwareHandler extends IdleStateAwareChannelHandler { 

    @Override 
    public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) { 
     if (e.getState() == IdleState.READER_IDLE) { 
      e.getChannel().write("heartbeat-reader_idle"); 
     } 
     else if (e.getState() == IdleState.WRITER_IDLE) { 
      Logger.getLogger(IdleStateAwareHandler.class.getName()).log(
        Level.WARNING, "WriteIdle detected, closing channel"); 
      e.getChannel().close(); 
      e.getChannel().write("heartbeat-writer_idle"); 
     } 
     else if (e.getState() == IdleState.ALL_IDLE) { 
      e.getChannel().write("heartbeat-all_idle"); 
     } 
    } 
} 

管道:

public class ICAPClientChannelPipeline implements ICAPClientPipeline { 

     ICAPClientHandler icapClientHandler; 
     ChannelPipeline pipeline; 

     public ICAPClientChannelPipeline(){ 
      icapClientHandler = new ICAPClientHandler(); 
     pipeline = pipeline(); 
      pipeline.addLast("idleStateHandler", new IdleStateHandler(new HashedWheelTimer(10, TimeUnit.MILLISECONDS), 5, 5, 5)); 
      pipeline.addLast("idleStateAwareHandler", new IdleStateAwareHandler()); 
      pipeline.addLast("encoder",new IcapRequestEncoder()); 
      pipeline.addLast("chunkSeparator",new IcapChunkSeparator(1024*4)); 
      pipeline.addLast("decoder",new IcapResponseDecoder()); 
      pipeline.addLast("chunkAggregator",new IcapChunkAggregator(1024*4)); 
      pipeline.addLast("handler", icapClientHandler);    
     } 

     @Override 
    public ChannelPipeline getPipeline() throws Exception { 
      return pipeline; 
    }      
} 

此檢測到任何讀或5秒後寫通道上的空閒狀態。 正如你所看到的,它有點ICAP特定的,但這個問題並不重要。

反應到空閒事件我需要以下監聽器:

channel.getCloseFuture().addListener(new ChannelFutureListener() { 
    @Override 
    public void operationComplete(ChannelFuture future) throws Exception { 
      doSomething(); 
    } 
});