netty(十三)tcp心跳实践

理论模型:https://www.cnblogs.com/silyvin/p/9605033.html

本次作实践,序列号承接 netty(十一)protobuf 

客户端:

                    pipeline.addLast(new IdleStateHandler(61, 30, 0, TimeUnit.SECONDS));
                    pipeline.addLast(new ClientHeartbeatHandler());

                    //处理类
                    pipeline.addLast(new ClientHandler4Heart());

  

需要Read和Write idle都设置,因为我们的心跳是由客户端主动发送的

 

public class ClientHeartbeatHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void userEventTriggered(final ChannelHandlerContext ctx, Object evt) throws Exception {

        if(evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if(event.state() == IdleState.WRITER_IDLE) {
                System.out.println("* CLIENT WRITER_IDLE send msg heart_beat...");
                sendHeartbeat(ctx);
            } else if (event.state() == IdleState.READER_IDLE) {
                System.out.println("* CLIENT has not receive SERVER msg, so CLOSE\n");
                ctx.close();
            }
        }
    }

    private void sendHeartbeat(final ChannelHandlerContext ctx) {

        MyBaseProto.BaseProto.Builder builder = MyBaseProto.BaseProto.newBuilder();
        builder.setCode(0);
        builder.setMsg("Heartbeat");
        ctx.channel().writeAndFlush(builder.build());
    }
}

  30s主动发送一次心跳,61s未收到任何消息(含心跳-&-普通消息)即close连接

public class ClientHandler4Heart extends SimpleChannelInboundHandler<MyBaseProto.BaseProto> {

    //接受服务端发来的消息
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MyBaseProto.BaseProto msg) throws Exception {

        if("Heartbeat".equals(msg.getMsg())) {
            System.out.println("* CLIENT receive back heart");
        } else {
            System.out.println("SERVER'S general msg RESPONSE : "+ msg.toString());
        }
    }

    //与服务器建立连接
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //给服务器发消息
        MyBaseProto.BaseProto.Builder builder = MyBaseProto.BaseProto.newBuilder();
        builder.setCode(1);
        builder.setMsg("hello");
        ctx.channel().writeAndFlush(builder.build());
    }

  active后随即发送一条普通消息,read函数中,对心跳与普通消息分别处理

服务端:

                    pipeline.addLast(new IdleStateHandler(61, 0, 0, TimeUnit.SECONDS));
                    pipeline.addLast(new ServerHeartbeatHandler());
                    //处理类
                    pipeline.addLast(new ServerHandler4V2Heart());

  服务端仅需要ReadIdle

public class ServerHeartbeatHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void userEventTriggered(final ChannelHandlerContext ctx, Object evt) throws Exception {

        if(evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                System.out.println("* SERVER has not receive CLIENT msg, so CLOSE\n");
                ctx.close();
            }
        }
    }
}

  61s,即连续2个30s未收到任何消息(普通消息&心跳)后(1s作冗余时间储备),close连接

public class ServerHandler4V2Heart extends SimpleChannelInboundHandler<MyBaseProtoV2.BaseProto> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MyBaseProtoV2.BaseProto msg) throws Exception {

        if("Heartbeat".equals(msg.getMsg())) {
            System.out.println("* SERVER receive heart and send back");
            writeAndFlush(ctx, msg);
        } else {
            System.out.println("general msg, send RESPONSE --------\n"+msg.toString());
            MyBaseProtoV2.BaseProto.Builder builder = MyBaseProtoV2.BaseProto.newBuilder();
            builder.setCode(msg.getCode() + 1);
            builder.setMsg("SERVER:" + msg.getMsg());
            writeAndFlush(ctx, builder.build());
        }
    }

  对心跳和普通消息分别处理

 

运行2分钟:

客户端:

SERVER'S general msg RESPONSE : code: 2
msg: "SERVER:hello"

* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT receive back heart
* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT receive back heart
* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT receive back heart

 

服务端:

server start ......
channelActive
general msg, send RESPONSE --------
code: 1
msg: "hello"

* SERVER receive heart and send back
* SERVER receive heart and send back
* SERVER receive heart and send back

 

干掉服务端的返回心跳,以模拟一段时间后断网断电情况:

public class ServerHandler4V2Heart extends SimpleChannelInboundHandler<MyBaseProtoV2.BaseProto> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MyBaseProtoV2.BaseProto msg) throws Exception {

        if("Heartbeat".equals(msg.getMsg())) {
//            System.out.println("* SERVER receive heart and send back");
//            writeAndFlush(ctx, msg);

  

客户端:

SERVER'S general msg RESPONSE : code: 2
msg: "SERVER:hello"

* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT has not receive SERVER msg, so CLOSE

channelInactive

 

服务端:

server start ......
channelActive
general msg, send RESPONSE --------
code: 1
msg: "hello"

channelInactive

 

2次未收到心跳回复1s后,client close channel

 

 

干掉客户端的发送心跳,模拟断网断电:

                //    pipeline.addLast(new IdleStateHandler(61, 30, 0, TimeUnit.SECONDS));
                    pipeline.addLast(new ClientHeartbeatHandler());

                    //处理类
                    pipeline.addLast(new ClientHandler4Heart());

  

客户端:

SERVER'S general msg RESPONSE : code: 2
msg: "SERVER:hello"

channelInactive

 

服务端:

server start ......
channelActive
general msg, send RESPONSE --------
code: 1
msg: "hello"

* SERVER has not receive CLIENT msg, so CLOSE

channelInactive

 

61s未收到任何消息后,server close channel

posted on 2018-10-16 11:18  silyvin  阅读(366)  评论(0)    收藏  举报