package com.lyncc.netty.keepalive;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
public class Heartbeat extends SimpleChannelInboundHandler<KeepAliveMessage>{
//失败计数器:未收到client端发送的ping请求
private int unRecPingTimes = 0 ;
//每个chanel对应一个线程,此处用来存储对应于每个线程的一些基础数据,此处不一定要为KeepAliveMessage对象
ThreadLocal<KeepAliveMessage> localMsgInfo = new ThreadLocal<KeepAliveMessage>();
// 定义客户端没有收到服务端的pong消息的最大次数
private static final int MAX_UN_REC_PING_TIMES = 3;
@Override
protected void channelRead0(ChannelHandlerContext ctx, KeepAliveMessage msg) throws Exception {
System.out.println(ctx.channel().remoteAddress() + " Say : sn=" + msg.getSn()+",reqcode="+msg.getReqCode());
if(Utils.notEmpty(msg.getSn())&&msg.getReqCode()==1){
msg.setReqCode(Constants.RET_CODE);
ctx.channel().writeAndFlush(msg);
// 失败计数器清零
unRecPingTimes = 0;
if(localMsgInfo.get()==null){
KeepAliveMessage localMsg = new KeepAliveMessage();
localMsg.setSn(msg.getSn());
localMsgInfo.set(localMsg);
}
}else{
ctx.channel().close();
}
}
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.READER_IDLE) {
/*读超时*/
System.out.println("===服务端===(READER_IDLE 读超时)");
// 失败计数器次数大于等于3次的时候,关闭链接,等待client重连
if(unRecPingTimes >= MAX_UN_REC_PING_TIMES){
System.out.println("===服务端===(读超时,关闭chanel)");
// 连续超过N次未收到client的ping消息,那么关闭该通道,等待client重连
ctx.channel().close();
}else{
// 失败计数器加1
unRecPingTimes++;
}
} else if (event.state() == IdleState.WRITER_IDLE) {
/*写超时*/
System.out.println("===服务端===(WRITER_IDLE 写超时)");
} else if (event.state() == IdleState.ALL_IDLE) {
/*总超时*/
System.out.println("===服务端===(ALL_IDLE 总超时)");
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("错误原因:"+cause.getMessage());
if(localMsgInfo.get()!=null){
/*
* 从管理集合中移除设备号等唯一标示,标示设备离线
*/
// TODO
}
ctx.channel().close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client active ");
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// 关闭,等待重连
ctx.close();
if(localMsgInfo.get()!=null){
/*
* 从管理集合中移除设备号等唯一标示,标示设备离线
*/
// TODO
}
System.out.println("===服务端===(客户端失效)");
}
}