前言
在之前的文章已经讲过了mina
长连接的相关知识,大家感兴趣的话,可以参看以下文章
MINA实现TCP长连接(一)——客户端实现
MINA实现TCP长连接(二)——服务端实现
MINA实现TCP长连接(三)——数据断包粘包问题
MINA实现TCP长连接(四)——断开重连
为了让长链接实现在线保活,时刻保持其连接活性,接下来我们就讲讲mina
长连接的心跳机制
今天涉及以下内容:
- 心跳机制种类
- 心跳机制在客户端和服务端涉及的类
- 心跳机制在客户端和服务端的实现
- 效果图个项目结构图
- 涉及机制的几个类源码
先来波效果图
一.心跳机制种类
mina
提供一个过滤器类org.apache.mina.filter.keepalive.KeepAliveMessageFactory
,此类具备在IO空闲的时候发送并且反馈心跳包。
KeepAliveMessageFactory
接口主要有以下几个方法:
boolean isRequest(IoSession ioSession, Object o)
boolean isResponse(IoSession ioSession, Object o)
Object getRequest(IoSession ioSession)
Object getResponse(IoSession ioSession, Object o)
心跳机制主要分为下面几类:
1.1 active 活跃型
读取通道空闲时发送心跳请求,一旦心跳请求被发出,若在keepAliveRequestTimeout
内未收到心跳反馈,KeepAliveRequestTimeoutHandler
将会被调用.心跳包被接收后,心跳反馈会立刻发出。
在此心跳机制下,KeepAliveMessageFactory
类中的getRequest(IoSession ioSession)
与getResponse(IoSession ioSession, Object o)
必须返回非空
1.2 semi-active 半活跃型
读取通道空闲时发送心跳请求。发送心跳请求单不关注心跳反馈,当一个心跳请求包被接收后,心跳反馈立马发出。
在此机制下,KeepAliveMessageFactory
类中的getRequest(IoSession ioSession)
与getResponse(IoSession ioSession, Object o)
必须返回非空。并且心跳包请求后超时无反馈的处理机制设置为KeepAliveRequestTimeoutHandler.NOOP
(不做任何处理), KeepAliveRequestTimeoutHandler.LOG
(只输出警告信息不做其他处理)
1.3 passive 被动型
当前IO不希望主动发送心跳请求,但是当接受到一个心跳请求后,那么该心跳反馈也会立即发出。
在此机制下, KeepAliveMessageFactory
类中的getRequest(IoSession ioSession)
必须反馈null
,getResponse(IoSession ioSession, Object o)
必须返回非空。
1.4 deaf speaker 聋子型
当前IO会主动发送心跳请求,但是不想发送任何心跳反馈。
在此机制下,KeepAliveMessageFactory
类中的getRequest(IoSession ioSession)
与getResponse(IoSession ioSession, Object o)
必须返回null
。并且KeepAliveRequestTimeoutHandler
设置为DEAF_SPEAKER
1.5 sient-listener 持续监听型
既不想发送心跳请求也不想发送心跳反馈。
在此机制下,KeepAliveMessageFactory
类中的getRequest(IoSession ioSession)
与getResponse(IoSession ioSession, Object o)
必须返回null
。
心跳包请求超时后的处理机制:接口KeepAliveRequestTimeoutHandler
,一般该处理主要是针对能够发送心跳请求的心跳机制。
1.CLOSE:关闭连接
2,LOG:输出警告信息
3,NOOP:不做任何处理
4,EXCEPTION:抛出异常
5,DEAF_SPEAKER:一个特殊的处理,停止当前过滤器对对心跳反馈监听,因此让过滤器丢失请求超时的侦测功能。(让其变成聋子)
6,keepAliveRequestTimeout(KeepAliveFilter filter, IoSession session); 自定义处理
二.心跳机制在客户端和服务端涉及的类
以被动型(passive 被动型
)为例,则客户端涉及到的心跳类有:
ClientHeartBeatFactory:实现KeepAliveMessageFactory
接口,处理客户端的心跳包收发逻辑
服务端涉及到了类有:
ServerHeartBeatFactory:实现KeepAliveMessageFactory
接口,处理服务端的心跳包收发逻辑
三.心跳机制在客户端和服务端的实现
客户端连接设置心跳机制如下:
public class TempActivity extends AppCompatActivity implements View.OnClickListener{
private TextView mTv;
private Button mBtn1;
private Button mBtn2;
//声明tcp客户端操作对象和配置对象
private TmClientConfig mConfig;
private TmClientManager mTmClientManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_temp);
//初始化控件
initView();
//初始化数据
initData();
//设置监听
setListener();
}
/**初始化控件**/
private void initView(){
mTv=findViewById(R.id.tv);
mBtn1=findViewById(R.id.btn1);
mBtn2=findViewById(R.id.btn2);
}
/**初始化数据**/
private void initData() {
//初始化tcp配置
mConfig = new TmClientConfig.Builder(TempActivity.this)
.setIp("192.168.50.152")//设置服务端ip
.setPort(9124)//设置端口(0-65535)之间
// .setConnectTimeOut(30000)//设置连接超时时间,单位毫秒,默认30000,即30秒
// .setCharsetName("UTF-8")//设置字符集,默认为 “UTF-8”
// .setReadBufferSize(2048)//设置接收数据缓存区,默认2048
.setHeartBeat(true)//设置是否开启心跳机制,默认false,即关闭
.setHbDelayTime(10)//设置心跳包发送时间间隔,默认10秒(设置开启心跳机制后才生效)
.setHbBackTime(5)//设置心跳包接收时间间隔,默认5秒(设置开启心跳机制后才生效)
//设置发送和接收心跳包数据的处理(设置开启心跳机制后才生效)
.setChbListener(new ClientHeartBeatFactory.OnClientHeartBeatListener() {
@Override
public boolean isResponse(IoSession ioSession, Object obj) {
//客户端关注请求反馈,因此判断mesaage是否是反馈包
String message=obj.toString();
if("MinaServer".equals(message)){
return true;
}
return false;
}
@Override
public Object getRequest(IoSession ioSession) {
//获取心跳请求包 non-null
return "MinaClient";
}
})
//设置mina客户端接收数据监听
.setCmrListener(new TmClientHandler.OnMessageReceivedListener() {
@Override
public void messageReceived(IoSession session, Object message) {
//接收服务端消息
//......
LogUtil.i("======我是服务端返回消息==message=" + message.toString());
runOnUiThread(new Runnable() {
@Override
public void run() {
mTv.setText(message.toString());
}
});
}
}).build();
//初始化操作对象
mTmClientManager = new TmClientManager(mConfig);
}
/**设置监听**/
private void setListener(){
mBtn1.setOnClickListener(this);
mBtn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1://测试1
LogUtil.i("=======测试====1===");
test();
break;
case R.id.btn2://测试2
String result="我是中国人啊你是谁,我是亚瑟,你知道么,大家好一切都号";
String result1="abc";
//给服务端发送消息
SessionManager.getInstance().writeToServer(result1);
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//断开连接
mTmClientManager.disConnect();
}
/**测试**/
private void test(){
ToastUtil.shortShow("准备连接啊");
new Thread(new Runnable() {
@Override
public void run() {
//连接服务端
mTmClientManager.connect();
}
}).start();
}
}
服务端设置心跳机制调用代码如下:
public class TestJava {
public static void main(String[] args) {
TmServerManager tmServerManager = new TmServerManager();
tmServerManager.setPort(9124)
.setCharsetName("UTF-8")//设置字符编码集,若不设置则默认 UTF-8
.setReadBufferSize(2048)//设置接收缓存区大小,不设置的话默认为 2048
.setIdleTime(10)//设置服务回到空闲状态时间间隔,不设置则默认10秒
.setHeartBeat(true)//是否开启心跳机制,默认不开启
.setHbDelayTime(10)//设置接收心跳时间间隔(单位秒),若不设置则默认10秒(心跳开启生效)
//心跳反馈(心跳开启生效)
.setOnServerHeartBeatListener(new ServerHeartBeatFactory.OnServerHeartBeatListener() {
@Override
public boolean isResponse(IoSession ioSession, Object obj) {
//判断是否心跳请求包 是的话返回true
String message = obj.toString();
if ("MinaClient".equals(message)) {
return true;
}
return false;
}
@Override
public Object getRequest(IoSession ioSession) {
//根据心跳请求request 反回一个心跳反馈消息 non-null
return "MinaServer";
}
})
//通讯应答
.setOnTmsHandlerListener(new TmServerHandler.OnTmsHandlerListener() {
@Override
public String messageHandler(IoSession session, Object message) {
System.out.println("======我是收到消息====message="+message.toString());
String response=message.toString();
if(response!=null){
//服务端做出应答
return "我是服务端的亚瑟";
}
return null;
}
}).start();//启动服务
}
}
四.效果图个项目结构图
五.涉及机制的几个类源码
主要是客户端与服务端的两个心跳机制类:ClientHeartBeatFactory
与ServerHeartBeatFactory
。
客户端ClientHeartBeatFactory
源码如下: