我创建了一个SimpleChannelInboundHandler类型的入站处理程序,并将其添加到管道中。我的意图是每次建立连接时,都希望发送一个称为会话打开消息的应用程序消息,并使连接准备好发送实际消息。为此,请使用上述入站处理程序 跨越channelActive()发送会话打开消息,作为响应,我将收到一个会话打开确认消息。只有在那之后,我才能够发送任何数量的实际业务消息。我正在使用FixedChannelPool并按如下所示进行初始化。这在启动时效果很好。但是,如果远程主机关闭了连接,此后,如果发送了一条消息,调用下面的sendMessage(),则该消息甚至在会话打开消息通过channelActive()之前就已发送,并获得了响应。因此,服务器将忽略该消息,因为发送业务消息时会话尚未打开。
我要寻找的是,池应该仅返回那些已调用channelActive()事件的通道,该事件已经发送了会话打开消息,并且已经从服务器获取了会话打开确认消息。如何处理这种情况?
public class SessionHandler extends SimpleChannelInboundHandler<byte[]> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
if (ctx.channel().isWritable()) {
ctx.channel().writeAndFlush("open session message".getBytes()).;
}
}
}
// At the time of loading the applicaiton
public void init() {
final Bootstrap bootStrap = new Bootstrap();
bootStrap.group(group).channel(NioSocketChannel.class).remoteAddress(hostname, port);
fixedPool = new FixedChannelPool(bootStrap, getChannelHandler(), 5);
// This is done to intialise connection and the channelActive() from above handler is invoked to keep the session open on startup
for (int i = 0; i < config.getMaxConnections(); i++) {
fixedPool.acquire().addListener(new FutureListener<Channel>() {
@Override
public void operationComplete(Future<Channel> future) throws Exception {
if (future.isSuccess()) {
} else {
LOGGER.error(" Channel initialzation failed...>>", future.cause());
}
}
});
}
}
//要实际发送消息,应用程序将调用以下方法。
public void sendMessage(final String businessMessage) {
fixedPool.acquire().addListener(new FutureListener<Channel>() {
@Override
public void operationComplete(Future<Channel> future) throws Exception {
if (future.isSuccess()) {
Channel channel = future.get();
if (channel.isOpen() && channel.isActive() && channel.isWritable()) {
channel.writeAndFlush(businessMessage).addListener(new GenericFutureListener<ChannelFuture>() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// success msg
} else {
// failure msg
}
}
});
fixedPool.release(channel);
}
} else {
// Failure
}
}
});
}
答案 0 :(得分:0)
如果没有特殊原因需要使用FixedChannelPool
,则可以使用其他数据结构(列表/映射)存储通道。发送打开的会话消息后,可以在数据结构中添加一个通道,并使用channelInactive
方法将其删除。
如果您需要在频道上执行批量操作,则可以使用ChannelGroup。
如果您仍然希望使用FixedChannelPool
,则可以在通道中设置是否发送打开消息的属性:
ctx.channel().attr(OPEN_MESSAGE_SENT).set(true);
您可以在sendMessage
函数中获得以下属性:
boolean sent = ctx.channel().attr(OPEN_MESSAGE_SENT).get();
,并且可以在channelInactive
中将其设置为false或将其删除。
注意OPEN_MESSAGE_SENT
是AttributeKey
:
public static final AttributeKey<Boolean> OPEN_MESSAGE_SENT = AttributeKey.valueOf("OPEN_MESSAGE_SENT");