天天看點

使用netty實作心跳檢查

項目背景:

硬體裝置和伺服器websocket長連接配接通訊

使用技術:

java/netty

心跳頻率和關閉時長:

看裝置接入數和業務要求,比如6秒一個心跳包,對方收到後也傳回一個心跳響應。雙方2.5個周期内沒收到資料則關閉各自連結。常用心跳周期如2s,4s,6s,8s,10s...

哪個來發:

根據我們業務,伺服器端來主動發心跳包。開始心跳周期可以設定長點,比如10s。如果業務需求心跳檢查要迅速,則修改伺服器端的心跳周期,裝置固件更新。對于未更新的裝置在一個關閉時長内可能會收到2個以上心跳包,不受影響。

代碼實作:

READ_IDEL_TIME_OUT=25s

WRITE_IDEL_TIME_OUT=15s

ALL_IDEL_TIME_OUT=10s

HEARTBEAT_REQUEST=“H”

HEARTBEAT_RESPONSE=“B”

 inboundHandler繼承的是SimpleChannelInboundHandler<TextWebSocketFrame> 類。

伺服器端:

step1.  pipeline初始化配置

pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));

step2.  在任何一個handler裡實作userEventTriggered方法

    @Override  

    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)  

            throws Exception {  

        if (evt instanceof IdleStateEvent) {  

            IdleStateEvent event = (IdleStateEvent) evt;  

            if (event.state().equals(IdleState.READER_IDLE)) {  

                //未進行讀操作  

                log.error("READER_IDLE");  

                // 逾時關閉channel  

                ctx.close();  

            } else if (event.state().equals(IdleState.WRITER_IDLE)) {  

                //log.error("WRITER_IDLE"); 

            } else if (event.state().equals(IdleState.ALL_IDLE)) {  

                //未進行讀寫  

                log.info("SEND HeartBeat:H"); 

                ctx.channel().writeAndFlush(new TextWebSocketFrame(HEARTBEAT_REQUEST));                

            }  

        }  

    } 

伺服器端:

step1.  pipeline初始化配置

pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));

step2.  在任何一個handler裡實作userEventTriggered方法

    @Override  

    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)  

            throws Exception {  

        if (evt instanceof IdleStateEvent) {  

            IdleStateEvent event = (IdleStateEvent) evt;  

            if (event.state().equals(IdleState.READER_IDLE)) {  

                //未進行讀操作  

                log.error("READER_IDLE");  

                // 逾時關閉channel  

                ctx.close();  

            } else if (event.state().equals(IdleState.WRITER_IDLE)) {  

                //log.error("WRITER_IDLE"); 

            } else if (event.state().equals(IdleState.ALL_IDLE)) {  

                //未進行讀寫             

            }  

        }  

    } 

step3.收到伺服器心跳後,響應

    @Override

    protected void channelRead0(ChannelHandlerContext arg0, TextWebSocketFrame arg1) throws Exception {

        // TODO Auto-generated method stub

        String txt=arg1.text();

        log.info("RECV:"+arg1.text());

        if (HEARTBEAT_REQUEST.equals(txt)){

            arg0.channel().writeAndFlush(new TextWebSocketFrame(HEARTBEAT_RESPONSE) ).sync();

            log.info("SEND:"+HEARTBEAT_RESPONSE);

        }

    }