主要逻辑

使用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. ABP 未能加载文件或程序集“System.ComponentModel.Annota, Version=4.2.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。

    切换System.ComponentModel.Annotations版本到4.4.1  重新编译即可

  2. [NOI2014][bzoj3670] 动物园 [kmp+next数组应用]

    题面 传送门 思路 首先,这题最好的一个地方,在于它给出的关于$next$的讲解实在是妙极......甚至可以说我的kmp是过了这道题以后才脱胎换骨的 然后是正文: 如何求$num$数组? 这道题的输 ...

  3. php中的对象赋值

    如果现在问你一个问题: <?php class A{ public $a = 1; } $a = new A(); $b = $a; $b->a = 3; print_r($a->a ...

  4. vi 使用介绍

    参考 <<vi编辑器使用介绍>>文本编辑器有很多,比如图形模式的gedit.kwrite.OpenOffice ,文本模式下的编辑器有vi.vim(vi的增强版本)和nano, ...

  5. 原生js实现tooltip提示框的效果

    在js的世界里面,每一个小的特效都那么微不足道,却又那么的令人向往与好奇.前端工程师的任务特别高大上,因为他们的一个小小的设计就会激发别人的求知欲.比如说我,只是随机一瞟,便看到了这个tooltip的 ...

  6. js 如何生成一个不重复的ID的函数

    在MongoDB中的ObjectID,可以理解为是一个不会重复的ID,这里有个链接http://www.jb51.net/article/101164.htm感兴趣可以去研究一下. 我今天要做的就是做 ...

  7. (三)Spring 依赖注入

    一.Spring框架本身有四大原则: 使用POJO进行轻量级和最小侵入式开发. 通过依赖注入和接口变成实现松耦合. 通过AOP和默认习惯进行声明式变成. 使用AOP和模板减少模式化代码. Spring ...

  8. java中的BitSet

    (1)BitSet类     大小可动态改变, 取值为true或false的位集合.用于表示一组布尔标志. 此类实现了一个按需增长的位向量.位 set 的每个组件都有一个 boolean 值.用非负的 ...

  9. linux mmap 详解【转】

    转自:http://blog.chinaunix.net/uid-20321537-id-3483405.html 一.前言mmap的具体实现以前在学习内核时学习过,但是对于其中的很多函数是一知半解的 ...

  10. Android系统启动过程【转】

    转自:http://www.cnblogs.com/bastard/archive/2012/08/28/2660389.html Android系统启动过程 首先Android框架架构图:(来自网上 ...