基于MINA实现server端心跳检测(KeepAliveFilter)
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完蛋了(至少从表面上看是这样)。
具体的源代码如下:
Server.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset; import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class Server { private static final int PORT = 9123;
/** 30秒后超时 */
private static final int IDELTIMEOUT = 30;
/** 15秒发送一次心跳包 */
private static final int HEARTBEATRATE = 15;
/** 心跳包内容 */
private static final String HEARTBEATREQUEST = "0x11";
private static final String HEARTBEATRESPONSE = "0x12";
private static final Logger LOG = LoggerFactory.getLogger(Server.class); public static void main(String[] args) throws IOException {
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.getSessionConfig().setReadBufferSize(1024);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE,
IDELTIMEOUT); acceptor.getFilterChain().addLast("logger", new LoggingFilter());
acceptor.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new TextLineCodecFactory())); KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();
//下面注释掉的是自定义Handler方式
// KeepAliveRequestTimeoutHandler heartBeatHandler = new
// KeepAliveRequestTimeoutHandlerImpl();
// KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory,
// IdleStatus.BOTH_IDLE, heartBeatHandler); KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory,
IdleStatus.BOTH_IDLE); //设置是否forward到下一个filter
heartBeat.setForwardEvent(true);
//设置心跳频率
heartBeat.setRequestInterval(HEARTBEATRATE); acceptor.getFilterChain().addLast("heartbeat", heartBeat); acceptor.setHandler(new MyIoHandler());
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("Server started on port: " + PORT);
} /**
* @ClassName KeepAliveMessageFactoryImpl
* @Description 内部类,实现KeepAliveMessageFactory(心跳工厂)
* @author cruise
*
*/
private static class KeepAliveMessageFactoryImpl implements
KeepAliveMessageFactory { @Override
public boolean isRequest(IoSession session, Object message) {
LOG.info("请求心跳包信息: " + message);
if (message.equals(HEARTBEATREQUEST))
return true;
return false;
} @Override
public boolean isResponse(IoSession session, Object message) {
// LOG.info("响应心跳包信息: " + message);
// if(message.equals(HEARTBEATRESPONSE))
// return true;
return false;
} @Override
public Object getRequest(IoSession session) {
LOG.info("请求预设信息: " + HEARTBEATREQUEST);
/** 返回预设语句 */
return HEARTBEATREQUEST;
} @Override
public Object getResponse(IoSession session, Object request) {
LOG.info("响应预设信息: " + HEARTBEATRESPONSE);
/** 返回预设语句 */
return HEARTBEATRESPONSE;
// return null;
} } /**
* 对应上面的注释
* KeepAliveFilter(heartBeatFactory,IdleStatus.BOTH_IDLE,heartBeatHandler)
* 心跳超时处理
* KeepAliveFilter 在没有收到心跳消息的响应时,会报告给的KeepAliveRequestTimeoutHandler。
* 默认的处理是 KeepAliveRequestTimeoutHandler.CLOSE
* (即如果不给handler参数,则会使用默认的从而Close这个Session)
* @author cruise
*
*/ // private static class KeepAliveRequestTimeoutHandlerImpl implements
// KeepAliveRequestTimeoutHandler {
//
//
// @Override
// public void keepAliveRequestTimedOut(KeepAliveFilter filter,
// IoSession session) throws Exception {
// Server.LOG.info("心跳超时!");
// }
//
// }
}
MyIoHandler.java
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class MyIoHandler extends IoHandlerAdapter{
private final static Logger log = LoggerFactory
.getLogger(MyIoHandler.class); @Override
public void sessionOpened(IoSession session) throws Exception { } @Override
public void sessionClosed(IoSession session) throws Exception { } @Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String ip = session.getRemoteAddress().toString();
log.info("===> Message From " + ip + " : " + message);
} }
启动Server后,运行telnet客户端连接到Server端,便可以测试心跳;
测试结果如下图:
基于MINA实现server端心跳检测(KeepAliveFilter)的更多相关文章
- 记录初试Netty(2)-服务端心跳检测
今天在在搭建的netty框架中添加心跳机制,特此记录一下: 1.什么是心跳机制? 心跳是在TCP长连接中,客户端和服务端定时向对方发送数据包通知对方自己还在线,保证连接的有效性的一种机制 在 ...
- Mina 系列(四)之KeepAliveFilter -- 心跳检测
Mina 系列(四)之KeepAliveFilter -- 心跳检测 摘要: 心跳协议,对基于CS模式的系统开发来说是一种比较常见与有效的连接检测方式,最近在用MINA框架,原本自己写了一个心跳协议实 ...
- Netty实现服务端客户端长连接通讯及心跳检测
通过netty实现服务端与客户端的长连接通讯,及心跳检测. 基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key.每 ...
- 通过netty实现服务端与客户端的长连接通讯,及心跳检测。
基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key.每次服务器端如果要向某个客户端发送消息,只需根据ClientId取出对应的S ...
- Hadoop基于Protocol Buffer的RPC实现代码分析-Server端
http://yanbohappy.sinaapp.com/?p=110 最新版本的Hadoop代码中已经默认了Protocol buffer(以下简称PB,http://code.google.co ...
- Hadoop基于Protocol Buffer的RPC实现代码分析-Server端--转载
原文地址:http://yanbohappy.sinaapp.com/?p=110 最新版本的Hadoop代码中已经默认了Protocol buffer(以下简称PB,http://code.goog ...
- 为什么说基于TCP的移动端IM仍然需要心跳保活?(转)
源:https://segmentfault.com/a/1190000006832547 为什么说基于TCP的移动端IM仍然需要心跳保活?
- 带你读AI论文丨LaneNet基于实体分割的端到端车道线检测
摘要:LaneNet是一种端到端的车道线检测方法,包含 LanNet + H-Net 两个网络模型. 本文分享自华为云社区<[论文解读]LaneNet基于实体分割的端到端车道线检测>,作者 ...
- Java: server/client 心跳机制实现 示例
心跳机制 心跳机制是定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性的机制. 大部分CS的应用需要心跳机制.心跳机制一般在Server和Client都要实现,两者实现原理 ...
随机推荐
- MySQL性能优化(七·下)-- 锁机制 之 行锁
一.行锁概念及特点 1.概念:给单独的一行记录加锁,主要应用于innodb表存储引擎 2.特点:在innodb存储引擎中应用比较多,支持事务.开销大.加锁慢:会出现死锁:锁的粒度小,并发情况下,产生锁 ...
- 接口调用 POST
/** * 接口调用 POST * @return [type] [description] */ public function portPhone(Request $request) { $pho ...
- 基于Laravel开发博客应用系列 —— 使用Bower+Gulp集成前端资源
本节我们将讨论如何将前端资源集成到项目中,包括前端资源的发布和引入.本项目将使用 Bower 和 Gulp 下载和集成jQuery.Bootstrap.Font Awesome 以及 DataTabl ...
- 深度学习基础系列(十)| Global Average Pooling是否可以替代全连接层?
Global Average Pooling(简称GAP,全局池化层)技术最早提出是在这篇论文(第3.2节)中,被认为是可以替代全连接层的一种新技术.在keras发布的经典模型中,可以看到不少模型甚至 ...
- JAVAEE——Lucene基础:什么是全文检索、Lucene实现全文检索的流程、配置开发环境、索引库创建与管理
1. 学习计划 第一天:Lucene的基础知识 1.案例分析:什么是全文检索,如何实现全文检索 2.Lucene实现全文检索的流程 a) 创建索引 b) 查询索引 3.配置开发环境 4.创建索引库 5 ...
- Django一些开发经验
总结一些 Django 开发的小经验.先说一些最最基础的吧. 使用 virtualenv 隔离开发环境 使用 pip 管理项目依赖,主要就是一个小技巧,使用 pip freeze > requi ...
- [ 原创 ]学习笔记-Android 学习笔记 Contacts (一)ContentResolver query 参数详解 [转载]
此博文转载自:http://blog.csdn.net/wssiqi/article/details/8132603 1.获取联系人姓名 一个简单的例子,这个函数获取设备上所有的联系人ID和联系人NA ...
- 《jQuery基础教程》读书笔记
最近在看<jQuery基础教程>这本书,做了点读书笔记以备回顾,不定期更新. 第一章第二章比较基础,就此略过了... 第三章 事件 jQuery中$(document).ready()与j ...
- 【BZOJ 1415】 1415: [Noi2005]聪聪和可可 (bfs+记忆化搜索+期望)
1415: [Noi2005]聪聪和可可 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1640 Solved: 962 Description I ...
- css平移动画的实现
参考这位大佬的帖子:https://www.jianshu.com/p/5d8e77ef7f84