前言

今天涉及以下内容:

心跳机制种类

心跳机制在客户端和服务端涉及的类

心跳机制在客户端和服务端的实现

效果图个项目结构图

涉及机制的几个类源码

先来波效果图

客户端心跳日志.png

服务端心跳日志.png

一.心跳机制种类

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();//启动服务
}
}

四.效果图个项目结构图

客户端心跳日志.png

服务端心跳日志.png

客户端项目结构图.png

服务端项目结构图.png

五.涉及机制的几个类源码

主要是客户端与服务端的两个心跳机制类:ClientHeartBeatFactory与ServerHeartBeatFactory。

客户端ClientHeartBeatFactory源码如下: