我有以下情况:
以这种方式打开新的频道连接:
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)
之前和之后添加日志语句来确认这一点。连接断开时,仅显示之前的日志语句。
造成这种情况的原因是什么?我以为这些调用都是异步并立即返回?我也试过NioClientSocketChannelFactory,行为相同。
我尝试使用channel.getCloseFuture()
但是听众永远不会被调用,我在使用channel.isOpen()
,channel.isConnected()
和channel.isWritable()
写入之前尝试检查频道总是如此......
如何解决这个问题?没有异常被抛出,也没有真正发生......像this one和this one这样的问题表明,如果没有心跳,就无法检测到通道断开。但我无法实现心跳,因为我无法改变服务器端。
环境:Netty 3,JDK 1.7
答案 0 :(得分:0)
好的,我上周解决了这个问题,所以我会为完整性添加答案。
我错了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");
}
}
}
PipeLine:
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();
}
});