netty利用IdleStateHandler实现pingPong

Posted by hcy on March 26, 2020

IdleStateHandler这个类能实现三种工作模式 长时间未读 长时间未写 长时间未读写,三种模式可以同时工作

看一下它的构造方法

1
2
3
4
5
6
7
8
   public IdleStateHandler(
            int readerIdleTimeSeconds,
            int writerIdleTimeSeconds,
            int allIdleTimeSeconds) {

        this(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds,
             TimeUnit.SECONDS);
    }

分别传递读超时,写超时,读写超时 的时间,当某种模式超时时会回掉下面这个方法,将事件传递过来。我们判断这个方法里的事件来判断是什么超时了。如果参数传0则表示不检测这一项。

1
2
3
 protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {
        ctx.fireUserEventTriggered(evt);
    }

改造成PingPongHandler

PingPongHandler 写超时时会发送Ping,如果一定时间没接收到Pong,则主动断开连接。

接收到的Pong除了刷新最后读时间外没有其他用处,在PingPongHandler后面添加一个SimpleChannelInboundHandler来忽略所有的Pong

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class PingPongHandler extends IdleStateHandler {

    private static Logger log = LoggerFactory.getLogger(PingPongHandler.class);
    private static int writeTimeOut = 10;
    private static int readTimeout = writeTimeOut * 4 + 2;

    public PingPongHandler() {
        super(readTimeout, writeTimeOut, 0);
    }

    /**
     * PingPongHandler这个类,利用了IdleStateHandler定时发送ping
     * 但是收到的Pong如果不处理会被继续向下传播,这里添加一个SimpleChannelInboundHandler<Pong>在此handler后面,来丢弃所有的Pong,并且能刷新最后读取时间。
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
        ctx.pipeline().addAfter(ctx.name(), null, new SimpleChannelInboundHandler<Pong>() {
            @Override
            protected void channelRead0(ChannelHandlerContext ctx, Pong msg) {
                log.debug("收到Pong");
            }
        });
    }

    /*
     * 长时间没写(写超时),则主动发送ping
     * 长时间没读(读超时),则断开连接
     * */
    @Override
    protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) {
        if (evt.state() == IdleState.WRITER_IDLE) {
            ctx.writeAndFlush(new Ping()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
        } else {
            log.debug("读超时断开连接:{}", evt);
            ctx.flush().close();
        }
    }

}

转载请注明出处:https://www.huangchaoyu.com/2020/03/26/netty利用IdleStateHandler实现pingPong/