2012-07-11 161 views
2

我設立使用OioClientSocketChannelFactory和 管道這樣的客戶端連接:Netty的阻斷客戶端

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

pipeline.addLast("encoder", new MessageEncoder()); 
pipeline.addLast("decoder", new MessageDecoder()); 
pipeline.addLast("manager", new FooClientManager()); 
BlockingReadHandler<Message> reader = new BlockingReadHandler<Message>(); 
pipeline.addLast("reader", reader); 
bootstrap.setPipeline(pipeline); 

的FooClientManager類(一個SimpleChannelHandler)發送關於連接(SimpleChannelHandler.channelConnected)握手消息,和有責任從服務器使用握手回覆(SimpleChannelHandler.messageReceived),而不將它傳遞給管道。我不希望API的用戶接收某些低級消息,這是FooClientManager的責任。

預計在連接之後,API的用戶現在將構造消息並調用channel.write()發送消息,reader.read()阻止等待答覆。

我遇到的問題是FooClientManager在API的用戶名爲channel.write()之前沒有看到握手應答,因爲從未執行過read()。

如果我在調用channel.write()之前調用reader.read(),它將無限期地阻塞,因爲FooClientManager不會發送消息,我試圖讀取管道。

處理阻塞客戶端IO和管道中可能消費消息的通道處理程序的最佳方法是什麼?

回答

1

當握手完成時,FooClientManager需要通知API用戶。一種選擇是讓API用戶實現一個傳入FooClientManager構造函數的接口。您始終可以創建此接口的默認實現,它的行爲類似於未來,並允許API用戶在握手完成之前阻止。

另一種選擇是讓FooClientManager在流水線上發送自定義消息,通知連接已準備就緒。然後API用戶在reader.read()上阻塞,直到它接收到消息。

0

感謝您的答案johnstlr!

這兩個解決方案的工作。我們實現的解決方案是在握手完成之前讓FooClientManager隊列寫入請求。然後它發送所有排隊的消息。

我們碰到的一個問題是,如果我們在握手完成之前排隊所有寫入請求,那麼當FooClientManaager調用channel.write()並且通過整個管道發送消息時,握手消息本身排隊。我們通過讓FooClientManager構造消息事件並將其直接發送到管道中的下一個處理程序來解決此問題:

ctx.sendDownstream(new DownstreamMessageEvent(ctx.getChannel(), new DefaultChannelFuture(ctx.getChannel(), false), msg, e.getChannel().getRemoteAddress())); 
+1

我很高興您找到了解決方案。另一個提示是,你也可以使用org.jboss.netty.channel.Channels.write(...)直接向管道中的下一個處理程序寫入消息。 – johnstlr 2012-07-13 08:02:42