2

我正在使用 OioClientSocketChannelFactory 和这样的管道设置客户端连接:

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 在调用 channel.write() 的 API 的用户之前没有看到握手回复,因为从未执行过 read()。

如果我在调用 channel.write() 之前调用 reader.read(),它会无限期地阻塞,因为 FooClientManager 不会发送我试图读取管道的消息。

处理阻塞客户端 IO 和管道中可能消耗消息的通道处理程序的最佳方法是什么?

4

2 回答 2

1

FooClientManager 需要在握手完成时通知 API 用户。一种选择是让 API 用户实现一个接口,该接口被传递到 FooClientManager 的构造函数中。您始终可以创建此接口的默认实现,该实现类似于未来,并允许 API 用户阻塞直到握手完成。

另一种选择是让 FooClientManager 向管道发送一条自定义消息,表明连接已准备好。然后 API 用户在 reader.read() 上阻塞,直到它收到消息。

于 2012-07-12T13:24:37.713 回答
0

感谢johnstlr的回答!

这两种解决方案都有效。我们实施的解决方案是让 FooClientManager 将写入请求排队,直到握手完成。然后它发送所有排队的消息。

我们遇到的一个问题是,如果我们将所有写入请求排队直到握手完成,那么当 FooClientManaager 调用 channel.write() 并且消息通过整个管道发送时,握手消息本身就会排队。我们通过让 FooClientManager 构造一个消息事件并将其直接发送到管道中的下一个处理程序来解决这个问题:

ctx.sendDownstream(new DownstreamMessageEvent(ctx.getChannel(), new DefaultChannelFuture(ctx.getChannel(), false), msg, e.getChannel().getRemoteAddress()));
于 2012-07-12T16:20:21.223 回答