0

我有以下情况:

以这种方式打开一个新的通道连接:

    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). 当连接断开时,只显示之前的日志语句。

  1. 这是什么原因造成的?我认为这些调用都是异步的并立即返回?我也试过 NioClientSocketChannelFactory,同样的行为。

  2. 我尝试使用channel.getCloseFuture()但从未调用过侦听器,我尝试在使用之前检查频道channel.isOpen()channel.isConnected()并且channel.isWritable()它们总是正确的......

  3. 如何解决这个问题?没有抛出异常,也没有真正发生任何事情......像thisthis这样的一些问题表明,如果没有心跳,就无法检测到通道断开连接。但是我无法实现心跳,因为我无法更改服务器端。

环境:Netty 3、JDK 1.7

4

1 回答 1

0

好的,我上周自己解决了这个问题,所以我会添加完整的答案。

我在 3 中错了。因为我认为我必须同时更改客户端和服务器端才能获得心跳。如本问题所述,您可以将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");
        }
    }
}

管道:

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();
    }
});
于 2013-09-25T08:42:04.690 回答