主要逻辑

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

实现的逻辑主要是:

服务器端方面

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

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

客户端方面

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

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

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

环境:netty5,tomcat7,jdk7,myeclipse

服务器端心跳处理类:

  1. public class HeartBeatRespHandler extends ChannelInboundHandlerAdapter {
  2. private  final Logger log=Logger.getLogger(HeartBeatRespHandler.class);
  3. //线程安全心跳失败计数器
  4. private AtomicInteger unRecPingTimes = new AtomicInteger(1);
  5. @Override
  6. public void channelRead(ChannelHandlerContext ctx, Object msg)
  7. throws Exception {
  8. NettyMessageProto message = (NettyMessageProto)msg;
  9. unRecPingTimes = new AtomicInteger(1);
  10. //接收客户端心跳信息
  11. if(message.getHeader() != null  && message.getHeader().getType() == Constants.MSGTYPE_HEARTBEAT_REQUEST){
  12. //清零心跳失败计数器
  13. log.info("server receive client"+ctx.channel().attr(SysConst.SERIALNO_KEY)+" ping msg :---->"+message);
  14. //接收客户端心跳后,进行心跳响应
  15. NettyMessageProto replyMsg = buildHeartBeat();
  16. ctx.writeAndFlush(replyMsg);
  17. }else{
  18. ctx.fireChannelRead(msg);
  19. }
  20. }
  21. /**
  22. * 事件触发器,该处用来处理客户端空闲超时,发送心跳维持连接。
  23. */
  24. @Override
  25. public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
  26. if (evt instanceof IdleStateEvent) {
  27. IdleStateEvent event = (IdleStateEvent) evt;
  28. if (event.state() == IdleState.READER_IDLE) {
  29. /*读超时*/
  30. log.info("===服务器端===(READER_IDLE 读超时)");
  31. unRecPingTimes.getAndIncrement();
  32. //客户端未进行ping心跳发送的次数等于3,断开此连接
  33. if(unRecPingTimes.intValue() == 3){
  34. ctx.disconnect();
  35. System.out.println("此客户端连接超时,服务器主动关闭此连接....");
  36. log.info("此客户端连接超时,服务器主动关闭此连接....");
  37. }
  38. } else if (event.state() == IdleState.WRITER_IDLE) {
  39. /*服务端写超时*/
  40. log.info("===服务器端===(WRITER_IDLE 写超时)");
  41. } else if (event.state() == IdleState.ALL_IDLE) {
  42. /*总超时*/
  43. log.info("===服务器端===(ALL_IDLE 总超时)");
  44. }
  45. }
  46. }
  47. /**
  48. * 创建心跳响应消息
  49. * @return
  50. */
  51. private NettyMessageProto buildHeartBeat(){
  52. HeaderProto header = HeaderProto.newBuilder().setType(Constants.MSGTYPE_HEARTBEAT_RESPONSE).build();
  53. NettyMessageProto message =NettyMessageProto.newBuilder().setHeader(header).build();
  54. return message;
  55. }

客户端心跳处理类:

  1. public class HeartBeatReqHandler extends ChannelHandlerAdapter {
  2. private  final Logger log=Logger.getLogger(HeartBeatReqHandler.class);
  3. //线程安全心跳失败计数器
  4. private AtomicInteger unRecPongTimes = new AtomicInteger(1);
  5. public void channelRead(ChannelHandlerContext ctx, Object msg)
  6. throws Exception {
  7. NettyMessageProto message = (NettyMessageProto)msg;
  8. //服务器端心跳回复
  9. if(message.getHeader() != null  && message.getHeader().getType() == Constants.MSGTYPE_HEARTBEAT_RESPONSE){
  10. //如果服务器进行pong心跳回复,则清零失败心跳计数器
  11. unRecPongTimes = new AtomicInteger(1);
  12. log.debug("client receive server pong msg :---->"+message);
  13. }else{
  14. ctx.fireChannelRead(msg);
  15. }
  16. }
  17. /**
  18. * 事件触发器,该处用来处理客户端空闲超时,发送心跳维持连接。
  19. */
  20. public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
  21. if (evt instanceof IdleStateEvent) {
  22. IdleStateEvent event = (IdleStateEvent) evt;
  23. if (event.state() == IdleState.READER_IDLE) {
  24. /*读超时*/
  25. log.info("===客户端===(READER_IDLE 读超时)");
  26. } else if (event.state() == IdleState.WRITER_IDLE) {
  27. /*客户端写超时*/
  28. log.info("===客户端===(WRITER_IDLE 写超时)");
  29. unRecPongTimes.getAndIncrement();
  30. //服务端未进行pong心跳响应的次数小于3,则进行发送心跳,否则则断开连接。
  31. if(unRecPongTimes.intValue() < 3){
  32. //发送心跳,维持连接
  33. ctx.channel().writeAndFlush(buildHeartBeat()) ;
  34. log.info("客户端:发送心跳");
  35. }else{
  36. ctx.channel().close();
  37. }
  38. } else if (event.state() == IdleState.ALL_IDLE) {
  39. /*总超时*/
  40. log.info("===客户端===(ALL_IDLE 总超时)");
  41. }
  42. }
  43. }
  44. private NettyMessageProto buildHeartBeat(){
  45. HeaderProto header = HeaderProto.newBuilder().setType(Constants.MSGTYPE_HEARTBEAT_REQUEST).build();
  46. NettyMessageProto  message = NettyMessageProto.newBuilder().setHeader(header).build();
  47. return message;
  48. }
  49. /**
  50. * 异常处理
  51. */
  52. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception{
  53. ctx.fireExceptionCaught(cause);
  54. }
  55. }
  1. <pre code_snippet_id="2489110" snippet_file_name="blog_20170719_2_6056366" name="code" class="java"><pre code_snippet_id="2489110" snippet_file_name="blog_20170719_2_6056366"></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre></pre>
  2. <pre></pre>
  3. <pre></pre>
  4. <pre></pre>
  5. <pre></pre>
  6. <link rel="stylesheet" href="http://static.blog.csdn.net/public/res-min/markdown_views.css?v=1.0">
 
 

版权声明:本文为博主原创文章,未经博主允许不得转载。

netty实现长连接心跳检的更多相关文章

  1. 转 互联网推送服务原理:长连接+心跳机制(MQTT协议)

    http://blog.csdn.net/zhangzeyuaaa/article/details/39028369 目录(?)[-] 无线移动网络的特点 android系统的推送和IOS的推送有什么 ...

  2. 互联网推送服务原理:长连接+心跳机制(MQTT协议)

    互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了 ...

  3. 移动互联网消息推送原理:长连接+心跳机制(MQTT协议)

    互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了 ...

  4. [转]Android TCP长连接 心跳机制及实现

    背景知识 智能手机上的长连接心跳和在Internet上的长连接心跳有什么不同 Android系统的推送和iOS的推送有什么区别 几种推送的实现方式 协议 1XMPP简介 2 MQTT简介 3移动端消息 ...

  5. Netty(一) SpringBoot 整合长连接心跳机制

    前言 Netty 是一个高性能的 NIO 网络框架,本文基于 SpringBoot 以常见的心跳机制来认识 Netty. 最终能达到的效果: 客户端每隔 N 秒检测是否需要发送心跳. 服务端也每隔 N ...

  6. Python WebSocket长连接心跳与短连接

    python websocket 安装 pip install websocket-client 先来看一下,长连接调用方式: ws = websocket.WebSocketApp("ws ...

  7. Android实现推送方式解决方案 - 长连接+心跳机制(MQTT协议)

    本文介绍在Android中实现推送方式的基础知识及相关解决方案.推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息. ...

  8. TCP keepalive长连接心跳保活

    比如:客户端与服务端进行握手时,经常无法握手成功,收不到回复: 需要建立保活机制. 1. 服务端Linux服务器新增系统内核参数配置. 在/etc/sysctl.conf文件中再添加如: #允许的持续 ...

  9. java Socket 长连接 心跳包 客户端 信息收发 demo

    今天写了个socket的测试小程序,代码如下 import java.io.IOException; import java.io.InputStream; import java.io.Output ...

随机推荐

  1. 文本处理grep命令

    this is a words file. words words to be , , , , , , , , , , beginning linux programming 4th edition ...

  2. [转]手写数字识别错误NameError: name 'mnist' is not defined

    转自:https://blog.csdn.net/coder_Gray/article/details/78562382 在Tensorflow上进行mnist数字识别实例时,出现如下错误 NameE ...

  3. PAT1032

    为了用事实说明挖掘机技术到底哪家强,PAT组织了一场挖掘机技能大赛.现请你根据比赛结果统计出技术最强的那个学校. 输入格式: 输入在第1行给出不超过105的正整数N,即参赛人数.随后N行,每行给出一位 ...

  4. 【.NET MVC分页】.NET MVC 使用pagelist 分页

    1.安装 2. 在NuGet程序包管理控制台 ,输入Install-Package PagedList.mvc 安装PagedList 和PageList.Mvc; 3. @{ Layout = nu ...

  5. Resize operation completed for file#

    Orale 12c RAC环境ALERT LOG中出现Resize operation completed for file# 查看数据库版本: BANNER CON_ID ------------- ...

  6. spring 解决中文乱码问题

    spring 解决中文乱码问题 使用spring的前提下在web.xml中配置 <filter> <filter-name>encodingFilter</filter- ...

  7. Codeforces 1158C Permutation recovery

    https://codeforces.com/contest/1158/problem/C 题目 已知 $p_1, p_2, \dots, p_n$ 是 $1$ 到 $n$ 的一个排列. 给出关于这个 ...

  8. HDU 4845 拯救大兵瑞恩(分层图状压BFS)

    拯救大兵瑞恩 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Sub ...

  9. BZOJ 3625 [Codeforces Round #250]小朋友和二叉树 ——NTT 多项式求逆 多项式开根

    生成函数又有奇妙的性质. $F(x)=C(x)*F(x)*F(x)+1$ 然后大力解方程,得到一个带根号的式子. 多项式开根有解只与常数项有关. 发现两个解只有一个是成立的. 然后多项式开根.求逆. ...

  10. [luoguP2587] [ZJOI2008]泡泡堂(贪心)

    传送门 贪心,很像田忌赛马那样,但是因为有平局加一分导致那样的贪心不好处理. 先将两个数组从小到大排序. 比较a最大和b最大,如果a比b大,那么直接赢掉 否则 比较a最小和b最小,如果a比b大,那么直 ...