MINA实现TCP长连接(五)——心跳机制

前言

在之前的文章已经讲过了mina长连接的相关知识,大家感兴趣的话,可以参看以下文章
MINA实现TCP长连接(一)——客户端实现
MINA实现TCP长连接(二)——服务端实现
MINA实现TCP长连接(三)——数据断包粘包问题
MINA实现TCP长连接(四)——断开重连
为了让长链接实现在线保活,时刻保持其连接活性,接下来我们就讲讲mina长连接的心跳机制

今天涉及以下内容:

  1. 心跳机制种类
  2. 心跳机制在客户端和服务端涉及的类
  3. 心跳机制在客户端和服务端的实现
  4. 效果图个项目结构图
  5. 涉及机制的几个类源码

先来波效果图


客户端心跳日志.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)必须反馈nullgetResponse(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

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

主要是客户端与服务端的两个心跳机制类:ClientHeartBeatFactoryServerHeartBeatFactory
客户端ClientHeartBeatFactory源码如下:

还有 26% 的精彩内容
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
支付 ¥3.00 继续阅读