Реализация сообщений keep-alive в Netty с помощью WriteTimeoutHandler

Я использую Netty 3.2.7. Я пытаюсь написать функциональность в моем клиенте таким образом, чтобы если по истечении определенного времени (скажем, 30 секунд) не было написано ни одного сообщения, на сервер отправлялось сообщение "keep-alive".

После некоторого копания я обнаружил, что WriteTimeoutHandler должен позволить мне сделать это. Я нашел это объяснение здесь: https://issues.jboss.org/browse/NETTY-79.

Пример, приведенный в документации Netty:

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():

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() никогда не вызывается.

Если посмотреть на источник WriteTimeoutHandler, то его реализация writeRequested() выглядит так:

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);
}

Похоже, что эта реализация говорит: "Когда запрашивается запись, установите новый таймаут. Когда запись успешна, отмените таймаут."

Используя отладчик, кажется, что именно это и происходит. Как только запись завершается, таймаут отменяется. Это не то поведение, которого я хочу. Мне нужно следующее поведение: "Если клиент не записал никакой информации в канал в течение 30 секунд, выбросить WriteTimeoutException."

Итак, не для этого ли предназначен WriteTimeoutHandler? Именно так я его интерпретировал из того, что прочитал в Интернете, но реализация, похоже, работает не так. Я использую его неправильно? Должен ли я использовать что-то другое? В нашей Mina-версии того же клиента, который я пытаюсь переписать, я вижу, что метод sessionIdle() переопределен для достижения нужного мне поведения, но этот метод недоступен в Netty.

12
задан ImmuneEntity 1 February 2012 в 20:24
поделиться