主要逻辑

使用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. html基础标签之head和body标签

    什么是标签标签是由一对尖括号包裹的单词构成的,也有一些单闭和标签,仅仅就自己出现就可以了,例如meta,link 1. 这里介绍了几种html语言里常见的head标签 <!DOCTYPE htm ...

  2. csapp 深入理解计算机系统 csapp.h csapp.c文件配置

    转载自   http://condor.depaul.edu/glancast/374class/docs/csapp_compile_guide.html Compiling with the CS ...

  3. JVM虚拟机系列(二)虚拟机的逻辑结构

    这个节日,终于把之前看的断断续续的JVM看的差不多了,在这里做一份笔记吧. JVM支持的数据类型: JVM运行时的数据区:

  4. Nginx概述与安装

    什么是Nginx 一款服务器软件,类似于Apache.Tomcat Nginx还是一款HTTP和反向代理服务器,同时也是一个代理邮件服务器.除了实现网站发布的功能外,还可以提供负载均衡. 所谓负载均衡 ...

  5. htmilunit-- 针对抓取js生成的数据

    public static String  getHtml(String html){        // 模拟一个浏览器          @SuppressWarnings("resou ...

  6. Python之文件操作:经验总结

    1.怎么判断读出来的文件是gbk还是utf-8编码 if content == u'中国'.encode('gbk'):     return 'gbk' elif content == u'中国'. ...

  7. vscode编辑器开发react时,设置使emmet支持自定义组件

    "emmet.triggerExpansionOnTab": true 在vscode用户配置当中配置这个,就可以了

  8. 阿里云将centos 7 自带的 php 5.4升级为 5.6

    1.php -v PHP 5.4.16 (cli) (built: Nov 6 2016 00:29:02) Copyright (c) 1997-2013 The PHP Group Zend En ...

  9. SQL查询数据后在连成字符串方法

    CREATE TABLE tb ( user_id INT, type_id TINYINT ); INSERT INTO tb (user_id, type_id) VALUES (1,11); I ...

  10. JavaScript真的要一统江湖了

    ttp://www.newsmth.net/nForum/#!article/Python/125347?p=4 标  题: JavaScript真的要一统江湖了 发信站: 水木社区 (Fri Sep ...