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() < 3){
- //发送心跳,维持连接
- 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);
- }
- }
- <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>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <link rel="stylesheet" href="http://static.blog.csdn.net/public/res-min/markdown_views.css?v=1.0">
版权声明:本文为博主原创文章,未经博主允许不得转载。
netty实现长连接心跳检的更多相关文章
- 转 互联网推送服务原理:长连接+心跳机制(MQTT协议)
http://blog.csdn.net/zhangzeyuaaa/article/details/39028369 目录(?)[-] 无线移动网络的特点 android系统的推送和IOS的推送有什么 ...
- 互联网推送服务原理:长连接+心跳机制(MQTT协议)
互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了 ...
- 移动互联网消息推送原理:长连接+心跳机制(MQTT协议)
互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了 ...
- [转]Android TCP长连接 心跳机制及实现
背景知识 智能手机上的长连接心跳和在Internet上的长连接心跳有什么不同 Android系统的推送和iOS的推送有什么区别 几种推送的实现方式 协议 1XMPP简介 2 MQTT简介 3移动端消息 ...
- Netty(一) SpringBoot 整合长连接心跳机制
前言 Netty 是一个高性能的 NIO 网络框架,本文基于 SpringBoot 以常见的心跳机制来认识 Netty. 最终能达到的效果: 客户端每隔 N 秒检测是否需要发送心跳. 服务端也每隔 N ...
- Python WebSocket长连接心跳与短连接
python websocket 安装 pip install websocket-client 先来看一下,长连接调用方式: ws = websocket.WebSocketApp("ws ...
- Android实现推送方式解决方案 - 长连接+心跳机制(MQTT协议)
本文介绍在Android中实现推送方式的基础知识及相关解决方案.推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息. ...
- TCP keepalive长连接心跳保活
比如:客户端与服务端进行握手时,经常无法握手成功,收不到回复: 需要建立保活机制. 1. 服务端Linux服务器新增系统内核参数配置. 在/etc/sysctl.conf文件中再添加如: #允许的持续 ...
- java Socket 长连接 心跳包 客户端 信息收发 demo
今天写了个socket的测试小程序,代码如下 import java.io.IOException; import java.io.InputStream; import java.io.Output ...
随机推荐
- PAT——乙级1001and1011
准备明年年初考PAT,练题呀,暂且先把LeetCode放下. 我是按照算法笔记这个教材刷的. B1001 1001 害死人不偿命的(3n+1)猜想 (15 point(s)) 卡拉兹(Callatz) ...
- MFC之HTTP文件上传
BOOL UploadFile(LPCTSTR strURL, LPCTSTR strLocalFileName) { // 如果URL为空或者文件不存在,直接返回 if (strURL == NUL ...
- 【bzoj3217】ALOEXT 替罪羊树套Trie树
题目描述 taorunz平时最喜欢的东西就是可移动存储器了……只要看到别人的可移动存储器,他总是用尽一切办法把它里面的东西弄到手. 突然有一天,taorunz来到了一个密室,里面放着一排可移动存储器, ...
- [LOJ#2330]「清华集训 2017」榕树之心
[LOJ#2330]「清华集训 2017」榕树之心 试题描述 深秋.冷风吹散了最后一丝夏日的暑气,也吹落了榕树脚下灌木丛的叶子.相识数年的Evan和Lyra再次回到了小时候见面的茂盛榕树之下.小溪依旧 ...
- bzoj 3704 昊昊的机油之GRST 贪心dp,思维
昊昊的机油之GRST Time Limit: 10 Sec Memory Limit: 1024 MBSubmit: 80 Solved: 33[Submit][Status][Discuss] ...
- 使用 swagger组件给asp.net webapi文档生成
1.名词解释 Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参数和模 ...
- 美食节(bzoj 2879)
Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽 ...
- linux把时间类型值转换为数值型
字符及字符串处理函数:字符及字符串处理函数的处理对象均为字符型数据,但其返回值类型各异.1.取子串函数:格式:substr(c,n1,n2)功能:取字符串C第n1个字符起的n2个字符.返回值类型是字符 ...
- 【HDOJ5510】Bazinga(KMP)
题意:给定n个由小写字母组成的字符串,第i个字符串为a[i],求最大的j满足存在1<=i<j,a[i]不是a[j]的子串,无解输出-1 T<=50,n<=500,len[i]& ...
- HTTP 错误 401.2 - Unauthorized
最近开始拾起Asp.net方面的知识,遇到如下这个问题 HTTP 错误 401.2 - Unauthorized 由于身份验证头无效,您无权查看此页. 解决方法: >IIS管理 >功能视图 ...