15815213711
2022-02-14 1c3164c096d405471ad7bb50fce86e321157d8a2
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.xncoding.pos.handler;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;
 
import com.xncoding.pos.utils.RunShellUtils;
import com.xncoding.pos.utils.SmsUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoop;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
 
public class HeartBeatClientHandler extends SimpleChannelInboundHandler<String>{
 
 
    private final ClientStarter clientStarter;
    private static final Logger logger = LoggerFactory.getLogger(HeartBeatClientHandler.class);
 
    public HeartBeatClientHandler(ClientStarter clientStarter) {
        this.clientStarter = clientStarter;
    }
 
    /**
     * 客户端监听写事件。也就是设置时间内没有与服务端交互则发送ping 给服务端
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent)evt).state();
            if(state == IdleState.ALL_IDLE) {
                ctx.writeAndFlush("PING");
                logger.info("PING SUCCESS");
            }
        }
        super.userEventTriggered(ctx, evt);
    }
    /**
     * channelInactive 被触发一定是和服务器断开了。分两种情况。一种是服务端close,一种是客户端close。
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx)  {
        try {
            super.channelInactive(ctx);
            logger.error("客户端与服务端断开连接,断开的时间为:"+(new Date()).toString());
            //1、重启服务
            RunShellUtils runShellUtils = new RunShellUtils();
            boolean runShell = runShellUtils.runShell();
            logger.info("runShell{}",runShell);
            //2、 发送短信给系统维护人员
            SmsUtils smsUtils = new SmsUtils();
            smsUtils.sendSms(runShell);
            //3、定时线程 断线重连
            final EventLoop eventLoop = ctx.channel().eventLoop();
            //设置断开连接后重连时间,此设置是断开连接分钟(120秒)后重连
            eventLoop.schedule(clientStarter::connect, 5, TimeUnit.SECONDS);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
 
    /**
     * 在服务器端不使用心跳检测的情况下,如果客户端突然拔掉网线断网(注意这里不是客户度程序关闭,而仅是异常断网)
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if(cause instanceof IOException) {
            System.out.println("server "+ctx.channel().remoteAddress()+"关闭连接");
        }
    }
 
    /**
     * 消息监控,监听服务端传来的消息(和netty版本有关,有的版本这个方法叫做clientRead0)
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
        if ("PONG".equals(msg)) {
            System.out.println("receive form server PONG");
        }
        ReferenceCountUtil.release(msg);
    }
}