列上两篇好文章

http://www.cnblogs.com/pricks/p/3832882.html

http://blog.csdn.net/cruise_h/article/details/13756219

心跳要解决的问题:说白了就是监控无效的连接并断开,多次超时无反应就断开的方式处理

MINA自带了对心跳协议的支持,可以对心跳做出细致的配置,本文在次基础上实现了server端对client端的心跳检测。

在开始之前先简单介绍下keepAlive的机制:

首先,需要搞清楚TCP keepalive是干什么用的。从名字理解就能够知道,keepalive就是用来检测一个tcp connection是否还连接正常。当一个tcp connection建立好之后,如果双方都不发送数据的话,tcp协议本身是不会发送其它的任何数据的,也就是说,在一个idle的connection上,两个socket之间不产生任何的数据交换。从另一个方面讲,当一个connection建立之后,链接双方可以长时间的不发送任何数据,比如几天,几星期甚至几个月,但该connection仍然存在。

所以,这就可能出现一个问题。举例来说,server和client建立了一个connection,server负责接收client的request。当connection建立好之后,client由于某种原因机器停机了。但server端并不知道,所以server就会一直监听着这个connection,但其实这个connection已经失效了。

keepalive就是为这样的场景准备的。当把一个socket设置成了keepalive,那么这个socket空闲一段时间后,它就会向对方发送数据来确认对方仍然存在。放在上面的例子中,如果client停机了,那么server所发送的keepalive数据就不会有response,这样server就能够确认client完蛋了(至少从表面上看是这样)。

那我项目心跳来说一下具体怎么做

MINA本身提供了一个过滤器类: org.apache.mina.filter.keepalive . KeepAliveFilter ,该过滤器用于在IO空闲的时候发送并且反馈心跳包(keep-alive request/response)。

说到KeepAliveFilter这个类有必要先说一说其构造函数,即实例化该类需要些什么,该类构造函数中参数有三个分别是: 
(1)KeepAvlieMessageFactory:   该实例引用用于判断接受与发送的包是否是心跳包,以及心跳请求包的实现 
(2)IdleStatus:                              该过滤器所关注的空闲状态,默认认为读取空闲。 即当读取通道空闲的时候发送心跳包 
(3)KeepAliveRequestTimeoutHandler: 心跳包请求后超时无反馈情况下的处理机制  默认为CLOSE  即关闭连接 

其实我们自己做下这两个接口的实现类就搞定了KeepAvlieMessageFactory、KeepAliveRequestTimeoutHandler

KeepAvlieMessageFactoryImpl中主要是定义心跳包的内容

KeepAliveRequestTimeoutHandlerImpl 主要是定义超时后的处理方式,通常是多次超时后就断开

看实例,我的消息类型固定为map,里面加一个cmd表示心跳的请求和响应

/**
* 心跳消息
*
* @author Administrator
*
*/
public class KeepAliveMessageFactoryImpl implements KeepAliveMessageFactory {
public static final int BEAT_REQ = 100000;
public static final int BEAT_RES = 100001;
private static final String key = "cmd"; private boolean notSendRequest;// 不发送请求,只接受心跳请求
private Map<String, Object> req = new HashMap<String, Object>();
private Map<String, Object> res = new HashMap<String, Object>(); public KeepAliveMessageFactoryImpl() {
req.put(key, BEAT_REQ);
res.put(key, BEAT_RES);
} public KeepAliveMessageFactoryImpl(boolean notSendRequest) {
req.put(key, BEAT_REQ);
res.put(key, BEAT_RES);
this.notSendRequest = notSendRequest;
} @Override
public Object getRequest(IoSession session) {
if (notSendRequest) {
//可以控制单项请求,也就是只有服务端发心跳,客户端不发
return null;
} else if (!session.containsAttribute(Response.CREDIT)) {
// 不可信的连接,不心跳
return null;
}
return req;
} @Override
public Object getResponse(IoSession session, Object request) {
return res;
} @Override
public boolean isRequest(IoSession session, Object message) {
if (message instanceof Map) {
Map msg = (Map) message;
Object obj = msg.get(key);
if (obj != null && obj instanceof Integer) {
if (((Integer) obj).intValue() == BEAT_REQ) {
// System.out.println("发送心跳响应:。。。。。。。。"+session.getRemoteAddress());
return true;
}
}
}
return false;
} @Override
public boolean isResponse(IoSession session, Object message) {
if (message instanceof Map) {
Map msg = (Map) message;
Object obj = msg.get(key);
if (obj != null && obj instanceof Integer) {
if (((Integer) obj).intValue() == BEAT_RES) {
// System.out.println("收到心跳响应:。。。。。。。。"+session.getRemoteAddress());
return true;
}
}
}
return false;
} }

再来看超时处理接口的实现类,超过3次超时就断开

public class KeepAliveRequestTimeoutHandlerImpl  implements
KeepAliveRequestTimeoutHandler {
private static Logger logger = LoggerFactory
.getLogger(RequestTimeoutCloseHandler.class); /**
* 超时几次关闭连接
*/
private int timeoutNum = 3; public void setTimeoutNum(int timeoutNum) {
this.timeoutNum = timeoutNum;
} public RequestTimeoutCloseHandler() {
} public RequestTimeoutCloseHandler(int timeoutNum) {
this.timeoutNum = timeoutNum;
} public void keepAliveRequestTimedOut(KeepAliveFilter filter,
IoSession session) throws Exception {
Integer num = (Integer) session
.getAttribute(KeepAliveFilter.TIMEOUT_NUM);
if (num == null || num >= timeoutNum) {
if (logger.isWarnEnabled()) {
logger.warn(com.youxigu.dynasty2.i18n.MarkupMessages.getString("RequestTimeoutCloseHandler_1"), filter
.getRequestTimeout(), session);
} Map<String, Object> params = new HashMap<String, Object>(3);
params.put("cmd", 1);
params.put("errCode", -9011);
params
.put("err",com.youxigu.dynasty2.i18n.MarkupMessages.getString("RequestTimeoutCloseHandler_2"));
session.write(params);
session.close(false);
//session.close(true);
}else{
if (logger.isWarnEnabled()) {
logger.warn(com.youxigu.dynasty2.i18n.MarkupMessages.getString("RequestTimeoutCloseHandler_0"),session,num);
}
}
}
} 加心跳过滤
		//在编解码过滤器之后加心跳过滤,如果connnection在处于空闲状态没10分钟发一次心跳请求,30秒无响应算超时,累计3次超时断开连接【在超时处理里做的】
KeepAliveFilter filter = new KeepAliveFilter(
new KeepAliveMessageFactoryImpl(), IdleStatus.BOTH_IDLE,
keepAliveHandler == null ? new KeepAliveRequestTimeoutHandlerImpl()
: keepAliveHandler, keepAliveRequestInterval <= 0 ? 600 : keepAliveRequestInterval, 30);
chain.addLast("ping", filter);

  

 

  

【MINA】心跳机制的更多相关文章

  1. rabbitmq 的心跳机制&应用

    官方文档说: If a consumer dies (its channel is closed, connection is closed, or TCP connection is lost) w ...

  2. zookeeper心跳机制流程梳理

    zookeeper心跳机制流程梳理 Processor链Chain protected void setupRequestProcessors() { RequestProcessor finalPr ...

  3. 一个Socket连接管理池(心跳机制)

    一个Socket连接管理池(心跳机制) http://cuisuqiang.iteye.com/blog/1489661

  4. ESFramework 开发手册(07) -- 掉线与心跳机制(转)

    虽然我们前面已经介绍完了ESFramework开发所需掌握的各种基础设施,但是还不够.想要更好地利用ESFramework这一利器,有些背景知识是我们必须要理解的.就像本文介绍的心跳机制,在严峻的In ...

  5. 判定生死的心跳机制 --ESFramework 4.0 快速上手(07)

    在Internet上采用TCP进行通信的系统,都会遇到一个令人头疼的问题,就是"掉线".而"TCP掉线"这个问题远比我们通常所能想象的要复杂的多 -- 网络拓扑 ...

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

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

  7. netty心跳机制测试

    netty中有比较完善的心跳机制,(在基础server版本基础上[netty基础--基本收发])添加少量代码即可实现对心跳的监测和处理. 1 server端channel中加入心跳处理机制 // Id ...

  8. Java: server/client 心跳机制实现 示例

    心跳机制 心跳机制是定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性的机制. 大部分CS的应用需要心跳机制.心跳机制一般在Server和Client都要实现,两者实现原理 ...

  9. Spark RPC框架源码分析(三)Spark心跳机制分析

    一.Spark心跳概述 前面两节中介绍了Spark RPC的基本知识,以及深入剖析了Spark RPC中一些源码的实现流程. 具体可以看这里: Spark RPC框架源码分析(二)运行时序 Spark ...

  10. Netty实现心跳机制

    netty心跳机制示例,使用Netty实现心跳机制,使用netty4,IdleStateHandler 实现.Netty心跳机制,netty心跳检测,netty,心跳 本文假设你已经了解了Netty的 ...

随机推荐

  1. linux命令getopts

    一.getopts 简介 由于shell命令行的灵活性,自己编写代码判断时,复杂度会比较高.使用内部命令 getopts 可以很方便地处理命令行参数.一般格式为: getopts options va ...

  2. POJ1149 PIGS

    想了好久啊...(#-.-) 开始想到m*n个点的构图,明显超时,于是考虑压缩节点个数 我们发现每个猪圈最后被有且只有一个人调整,于是想到对于一个人,连接他能调整的每个猪圈的上一个控制人.(不懂可以开 ...

  3. 系统时间不一致导致memcached的session不共享

    测试服务器需要做负载均衡,采用的是Nginx+Tomcat. 负载均衡配置成功之后,采用memcached配置session同步.总共4台服务器,三台服务器很顺利的配置成功,最后一台服务器死活不能共享 ...

  4. Android实例-解决启动黑屏问题(XE8+小米2)

    结果: 1.在启动时马上出现图片界面,但在出现程序界面前会有黑屏,大约有0.2秒左右. 实现: 1.建立2个文件:loading.png和styles.xml: ①其中loading.png是启动时替 ...

  5. java IO选择流的原则及其与IO流相关类的关系

    1 按照用途进行分类 1.1 按照数据的来源(去向)分类 是文件:FileInputStream, FileOutputStream, FileReader, FileWriter 是byte[]:B ...

  6. SpringMVC(二)

    今天在完成的工作的前提下,最终在睡觉前将SpringMVC和Mybatis整合了~~~ 其实就是按照从网上(参考http://www.toutiao.com/a6332703083554324737/ ...

  7. Remastersys打包你自己的ubuntu成iso文件,保存原来的所有配置

    你是不是辛辛苦苦地配好了ubuntu结果不久又重装,然后又重新配置很久呢? 笔者好不容易配置好了torch,但是换硬盘,于是就想到了将ubuntu打包成iso文件,下次直接安装,然后配置好的东西都搬过 ...

  8. Gitbook 使用入门

    GitBook 是一个基于 Node.js 的命令行工具,可使用 Github/Git 和 Markdown 来制作精美的电子书. 本书将简单介绍如何安装.编写.生成.发布一本在线图书. http:/ ...

  9. jeasyUI属性列表

    属性分为CSS片段和JS片段. CSS类定义:1.div easyui-window        生成一个window窗口样式.      属性如下:                   1)mod ...

  10. 设置UITabBarController的背景颜色

    if (IOS7) { self.tabBarController.tabBar.barTintColor = kTAB_BAR_GB_COLOR; }else{ self.tabBarControl ...