2012-06-29 57 views
2

我有一個關於綁定請求和上游處理程序收到channelBound事件的同步問題。由於處理程序需要使用對象來處理回調,因此我需要在處理程序可以接收到事件之前將對象附加到通道。下面的例子。在處理程序使用Netty接收事件之前,如何將對象附加到通道?

處理程序例如:

public class MyClientHandler extends SimpleChannelUpstreamHandler { 

    @Override 
    public void channelBound(ChannelHandlerContext ctx, ChannelStateEvent e) { 

     /* Problem: This can occur while the channel attachment is still null. */ 
     MyStatefulObject obj = e.getChannel().getAttachment(); 

     /* Do important things with attachment. */ 
    } 

} 

主要例如:

ClientBootstrap bootstrap = ... //Assume this has been configured correctly. 

ChannelFuture f = bootstrap.bind(new InetSocketAddress("192.168.0.15", 0)); 

/* It is possible the boundEvent has already been fired upstream 
* by the IO thread when I get here. 
*/ 
f.getChannel().setAttachment(new MyStatefulObject()); 

可能Soultions

,我想出了一個解決方案夫婦的來解決這個問題,但他們都親切「味道」這就是爲什麼我在這裏問是否有人有這樣乾淨的方式。

解決方案1:旋轉或阻止channelBound回調,直到附件不爲空。我不喜歡這個解決方案,因爲它連接了一個I/O worker。

解決方案2:使MyClientHandler進入雙向處理程序,並使用下游回調中的ThreadLocal獲取附件。我不喜歡這樣,因爲它依賴於Netty實現細節,請求線程用於觸發bindRequested事件。

我發現解決方案1比解決方案2更容忍。所以如果這是我需要做的,我會的。

有沒有一種簡單的方法來獲取通道引用,而無需先請求綁定或連接?

回答

2

是的,可能的是,boundEvent可以在將附件設置到通道之前獲取處理程序。

如果附件對於您打開的每個通道都非常具體,那麼您可以註冊未來綁定通道的未來監聽器,並在operationComplete() 上設置附件,方法是在不使用BootStraps的情況下設置所有內容。以下是EchoClient示例的修改版本,它工作正常。

 // Configure the client. 
    final NioClientSocketChannelFactory clientSocketChannelFactory = new NioClientSocketChannelFactory(
      Executors.newCachedThreadPool()); 


    // Set up the pipeline factory. 
    final ChannelPipelineFactory channelPipelineFactory = new ChannelPipelineFactory() { 
     public ChannelPipeline getPipeline() throws Exception { 
      return Channels.pipeline(
        new MyClientHandler()); 
     } 
    }; 

    ChannelPipeline pipeline = channelPipelineFactory.getPipeline(); 
    final Channel channel = clientSocketChannelFactory.newChannel(pipeline); 

    channel.getConfig().setPipelineFactory(channelPipelineFactory); 
    channel.getConfig().setOption("tcpNoDelay", true); 
    channel.getConfig().setOption("receiveBufferSize", 1048576); 
    channel.getConfig().setOption("sendBufferSize", 1048576); 

    ChannelFuture boundFuture = Channels.future(channel); 

    boundFuture.addListener(new ChannelFutureListener() { 
     @Override 
     public void operationComplete(ChannelFuture future) throws Exception { 
      if (future.isSuccess()) { 
       future.getChannel().setAttachment(new Object());// set the channel attachment 
      } 
     } 
    }); 


    channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(channel, boundFuture, ChannelState.BOUND, new InetSocketAddress(host, 0))); 

    ChannelFuture connectFuture = Channels.future(channel); 
    channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent(channel, connectFuture, ChannelState.CONNECTED, new InetSocketAddress(host, port))); 

    channel.getCloseFuture().awaitUninterruptibly(); 

    clientSocketChannelFactory.releaseExternalResources();// do not forget to do this 
+0

謝謝您的回答。通過直接使用ChannelFactory,我可以解決這個問題。 – Dev

+1

另外,你的第一個例子展示了同樣的同步問題。在調用'bind'之後,''channelBound'回調可能已經在監聽器被綁定到綁定將來之前被調用。同樣在我的第一個評論中,雖然你的第二個例子正是我所需要的。 – Dev

+0

我同意,對於錯誤感到抱歉。我已經刪除了第一個示例,以免混淆未來的觀衆:) –

2

使您的ChannelPipelineFactory實現接受構造函數參數並在其中指定附件。在所有其他處理程序前放置一個處理程序,並使第一個處理程序的channelOpen()方法設置附件,然後從管道中刪除第一個處理程序,因爲它不再需要。

相關問題