本文介绍了使用WriteTimeoutHandler在Netty中实现keep-alive消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是Netty 3.2.7。我正在尝试在我的客户端编写功能,如果在一定时间(例如30秒)之后没有写入消息,则会向服务器发送保持活动消息。

I am using Netty 3.2.7. I am trying to write functionality in my client such that if no messages are written after a certain amount of time (say, 30 seconds), a "keep-alive" message is sent to the server.

经过一番挖掘,我发现WriteTimeoutHandler应该让我这样做。我在这里找到了这样的解释:。

After some digging, I found that WriteTimeoutHandler should enable me to do this. I found this explanation here: https://issues.jboss.org/browse/NETTY-79.

Netty文档中给出的示例是:

The example given in the Netty documentation is:

public ChannelPipeline getPipeline() {
     // An example configuration that implements 30-second write timeout:
     return Channels.pipeline(
         new WriteTimeoutHandler(timer, 30), // timer must be shared.
         new MyHandler());
 }

在我的测试客户端中,我做到了这一点。在MyHandler中,我还覆盖了exceptionCaught()方法:

In my test client, I have done just this. In MyHandler, I also overrided the exceptionCaught() method:

public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
    if (e.getCause() instanceof WriteTimeoutException) {
        log.info("Client sending keep alive!");
        ChannelBuffer keepAlive = ChannelBuffers.buffer(KEEP_ALIVE_MSG_STR.length());
        keepAlive.writeBytes(KEEP_ALIVE_MSG_STR.getBytes());
        Channels.write(ctx, Channels.future(e.getChannel()), keepAlive);
    }
}

无论客户端在什么时间内没有写任何内容通道,我覆盖的exceptionCaught()方法永远不会被调用。

No matter what duration the client does not write anything to the channel, the exceptionCaught() method I have overridden is never called.

查看WriteTimeoutHandler的源代码,其writeRequested()实现是:

Looking at the source of WriteTimeoutHandler, its writeRequested() implementation is:

public void writeRequested(ChannelHandlerContext ctx, MessageEvent e)
        throws Exception {

    long timeoutMillis = getTimeoutMillis(e);
    if (timeoutMillis > 0) {
        // Set timeout only when getTimeoutMillis() returns a positive value.
        ChannelFuture future = e.getFuture();
        final Timeout timeout = timer.newTimeout(
                new WriteTimeoutTask(ctx, future),
                timeoutMillis, TimeUnit.MILLISECONDS);

        future.addListener(new TimeoutCanceller(timeout));
    }

    super.writeRequested(ctx, e);
}

在这里,似乎这个实现说,当请求写入时,当写入成功时,取消超时。

Here, it seems that this implementation says, "When a write is requested, make a new timeout. When the write succeeds, cancel the timeout."

使用调试器,看起来确实发生了这种情况。写入完成后,超时将被取消。这不是我想要的行为。我想要的行为是:如果客户端没有向通道写入任何信息30秒,则抛出WriteTimeoutException。

Using a debugger, it does seem that this is what is happening. As soon as the write completes, the timeout is cancelled. This is not the behavior I want. The behavior I want is: "If the client has not written any information to the channel for 30 seconds, throw a WriteTimeoutException."

那么,这不是WriteTimeoutHandler是什么对于?这就是我从在线阅读的内容中解释它的方式,但实现似乎并不是这样。我用错了吗?我应该用别的东西吗?在我试图重写的同一个客户端的Mina版本中,我看到sessionIdle()方法被覆盖以实现我想要的行为,但这种方法在Netty中不可用。

So, is this not what WriteTimeoutHandler is for? This is how I interpreted it from what I've read online, but the implementation does not seem to work this way. Am I using it wrong? Should I use something else? In our Mina version of the same client I am trying to rewrite, I see that the sessionIdle() method is overridden to achieve the behavior I want, but this method is not available in Netty.

推荐答案

我建议添加然后添加可以对空闲状态作出反应。这对我来说非常适用于许多不同的项目。

I would suggest to add the IdleStateHandler and then add your custom implementation of IdleStateAwareUpstreamHandler which can react on the idle state. This works out very well for me on many different projects.

javadocs列出了以下示例,您可以将其用作实现的基础:

The javadocs list the following example, that you could use as the base of your implementation:

public class MyPipelineFactory implements ChannelPipelineFactory {

    private final Timer timer;
    private final ChannelHandler idleStateHandler;

    public MyPipelineFactory(Timer timer) {
        this.timer = timer;
        this.idleStateHandler = new IdleStateHandler(timer, 60, 30, 0);
        // timer must be shared.
    }

    public ChannelPipeline getPipeline() {
        return Channels.pipeline(
            idleStateHandler,
            new MyHandler());
    }
}

// Handler should handle the IdleStateEvent triggered by IdleStateHandler.
public class MyHandler extends IdleStateAwareChannelHandler {

    @Override
    public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) {
        if (e.getState() == IdleState.READER_IDLE) {
            e.getChannel().close();
        } else if (e.getState() == IdleState.WRITER_IDLE) {
            e.getChannel().write(new PingMessage());
        }
    }
}

ServerBootstrap bootstrap = ...;
Timer timer = new HashedWheelTimer();
...
bootstrap.setPipelineFactory(new MyPipelineFactory(timer));
...

这篇关于使用WriteTimeoutHandler在Netty中实现keep-alive消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-10 18:38