atr netty长连接_netty实现长连接心跳检

主要逻辑:

使用netty实现长连接,主要靠心跳来维持服务器端及客户端连接。

实现的逻辑主要是:

服务器端方面:

1, 服务器在网络空闲操作一定时间后,服务端失败心跳计数器加1。

2, 如果收到客户端的ping心跳包,则清零失败心跳计数器,如果连续n次未收到客户端的ping心跳包,则关闭链路,释放资源,等待客户端重连。

客户端方面:

1, 客户端网络空闲在一定时间内没有进行写操作时,则发送一个ping心跳包。

2, 如果服务器端未在发送下一个心跳包之前回复pong心跳应答包,则失败心跳计数器加1。

3, 如果客户端连续发送n(此处根据具体业务进行定义)次ping心跳包,服务器端均未回复pong心跳应答包,则客户端断开连接,间隔一定时间进行重连操作,直至连接服务器成功。

环境:netty5,tomcat7,jdk7,myeclipse

服务器端心跳处理类:

public class HeartBeatRespHandler extends ChannelInboundHandlerAdapter {

private  final Logger log=Logger.getLogger(HeartBeatRespHandler.class);

//线程安全心跳失败计数器

private AtomicInteger unRecPingTimes = new AtomicInteger(1);

@Override

public void channelRead(ChannelHandlerContext ctx, Object msg)

throws Exception {

NettyMessageProto message = (NettyMessageProto)msg;

unRecPingTimes = new AtomicInteger(1);

//接收客户端心跳信息

if(message.getHeader() != null  && message.getHeader().getType() == Constants.MSGTYPE_HEARTBEAT_REQUEST){

//清零心跳失败计数器

log.info("server receive client"+ctx.channel().attr(SysConst.SERIALNO_KEY)+" ping msg :---->"+message);

//接收客户端心跳后,进行心跳响应

NettyMessageProto replyMsg = buildHeartBeat();

ctx.writeAndFlush(replyMsg);

}else{

ctx.fireChannelRead(msg);

}

}

/**

* 事件触发器,该处用来处理客户端空闲超时,发送心跳维持连接。

*/

@Override

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

if (evt instanceof IdleStateEvent) {

IdleStateEvent event = (IdleStateEvent) evt;

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

/*读超时*/

log.info("===服务器端===(READER_IDLE 读超时)");

unRecPingTimes.getAndIncrement();

//客户端未进行ping心跳发送的次数等于3,断开此连接

if(unRecPingTimes.intValue() == 3){

ctx.disconnect();

System.out.println("此客户端连接超时,服务器主动关闭此连接....");

log.info("此客户端连接超时,服务器主动关闭此连接....");

}

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

/*服务端写超时*/

log.info("===服务器端===(WRITER_IDLE 写超时)");

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

/*总超时*/

log.info("===服务器端===(ALL_IDLE 总超时)");

}

}

}

/**

* 创建心跳响应消息

* @return

*/

private NettyMessageProto buildHeartBeat(){

HeaderProto header = HeaderProto.newBuilder().setType(Constants.MSGTYPE_HEARTBEAT_RESPONSE).build();

NettyMessageProto message =NettyMessageProto.newBuilder().setHeader(header).build();

return message;

}

客户端心跳处理类:

public class HeartBeatReqHandler extends ChannelHandlerAdapter {

private  final Logger log=Logger.getLogger(HeartBeatReqHandler.class);

//线程安全心跳失败计数器

private AtomicInteger unRecPongTimes = new AtomicInteger(1);

public void channelRead(ChannelHandlerContext ctx, Object msg)

throws Exception {

NettyMessageProto message = (NettyMessageProto)msg;

//服务器端心跳回复

if(message.getHeader() != null  && message.getHeader().getType() == Constants.MSGTYPE_HEARTBEAT_RESPONSE){

//如果服务器进行pong心跳回复,则清零失败心跳计数器

unRecPongTimes = new AtomicInteger(1);

log.debug("client receive server pong msg :---->"+message);

}else{

ctx.fireChannelRead(msg);

}

}

/**

* 事件触发器,该处用来处理客户端空闲超时,发送心跳维持连接。

*/

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

if (evt instanceof IdleStateEvent) {

IdleStateEvent event = (IdleStateEvent) evt;

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

/*读超时*/

log.info("===客户端===(READER_IDLE 读超时)");

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

/*客户端写超时*/

log.info("===客户端===(WRITER_IDLE 写超时)");

unRecPongTimes.getAndIncrement();

//服务端未进行pong心跳响应的次数小于3,则进行发送心跳,否则则断开连接。

if(unRecPongTimes.intValue() 

//发送心跳,维持连接

ctx.channel().writeAndFlush(buildHeartBeat()) ;

log.info("客户端:发送心跳");

}else{

ctx.channel().close();

}

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

/*总超时*/

log.info("===客户端===(ALL_IDLE 总超时)");

}

}

}

private NettyMessageProto buildHeartBeat(){

HeaderProto header = HeaderProto.newBuilder().setType(Constants.MSGTYPE_HEARTBEAT_REQUEST).build();

NettyMessageProto  message = NettyMessageProto.newBuilder().setHeader(header).build();

return message;

}

/**

* 异常处理

*/

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception{

ctx.fireExceptionCaught(cause);

}

}

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值