主要逻辑

使用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. CentOS6.5 安装中文输入法

    直接转载他人文章:http://hi.baidu.com/dxqt58592/item/a85b96e72c423cc0baf37d3c centos 6.5使用yum安装中文输入法 1.需要root ...

  2. 【bzoj1531】[POI2005]Bank notes 多重背包dp

    题目描述 Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有n种面值的硬币,面值分别为b1, b2,..., bn. 但是每种硬币有数量限制,现在我们想要凑出面值 ...

  3. FZU Super A^B mod C(欧拉函数降幂)

    Problem 1759 Super A^B mod C Accept: 878    Submit: 2870 Time Limit: 1000 mSec    Memory Limit : 327 ...

  4. [SDOI2008][luogu2463] Sandy的卡片 [kmp]

    题面 传送门 思路 这道题里面有三个主要问题: 1.由"数值相等"变成了"加上一个整数以后数值相等"(减去等价于加负数) 2.由"最多匹配多少位(从第 ...

  5. 数组洗牌算法-shuffle

    数组洗牌,最近直接的想法是从数组随机取出一个元素,放到另一个数组中,但是这样取出的元素会有重复,必须采取一定的方法保证: 1. 元素不能重复2. 元素被抽取的概率相等,即随机性 数组洗牌经典算法有两种 ...

  6. 刷题总结—— Scout YYF I(poj3744 矩阵快速幂+概率dp)

    题目: Description YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate int ...

  7. 使用iview如何使左上的添加按钮和右上的搜索框和边框对齐

    使用iview如何使左上的添加按钮和右上的搜索框和边框对齐呢? 效果如下: 使用iview自带的Grid 栅格进行布局,但是由于按钮和搜索框的大小不正好是一个栅格的宽度,所以不是很好跳转,且栅格也不支 ...

  8. mongodb学习(3)--- NodeJs使用mongoose操作mongodb

    转载: https://cnodejs.org/topic/50c145ed637ffa4155c7eaee 首先对于以下错误说明(有写 db.close): Error: db object alr ...

  9. ios 上传视频或图片

    关于iOS如何实现视频和图片的上传, 我们先理清下思路 思路: #1. 如何获取图片? #2. 如何获取视频? #3. 如何把图片存到缓存路径中? #4. 如何把视频存到缓存路径中? #5. 如何上传 ...

  10. How Many to Be Happy?

    How Many to Be Happy? 时间限制: 1 Sec  内存限制: 128 MB 题目描述 Let G be a connected simple undirected graph wh ...