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