设定IdleStateHandler心跳检测每四秒进行一次写检测,如果四秒内write()方法未被调用则触发一次userEventTrigger()方法,实现客户端每四秒向服务端发送一次心跳消息
12个文件已修改
157 ■■■■■ 已修改文件
app/src/main/java/safeluck/drive/evaluation/MainActivity.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/fragment/TcpFragment.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/im/IMSClientBootstrap.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/im/IMSEventListener.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/im/IMessageProcessor.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/im/MessageProcessor.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/message/BinMessageBase.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/MainActivity.java
@@ -321,6 +321,7 @@
        MyLog.i(TAG,"TCP连接成功");
        //TODO 判断SPUtils 是否保存有des密码;如果没有则进行注册JKMessage0100,如果有密码则进行鉴权JKMessage0101
        String hexPwd = (String) SPUtils.get(this,SPUtils.DES_HEX_PWD,"");
        MessageProcessor.getInstance().addBeatHeart(10);
        if (TextUtils.isEmpty(hexPwd)){
            JKMessage0100 jkRegisterMessage = new JKMessage0100();
app/src/main/java/safeluck/drive/evaluation/fragment/TcpFragment.java
@@ -291,7 +291,7 @@
                    @Override
                    public void run() {
                        JKMessage0002 jkMessage0002 = new JKMessage0002();
                        jkMessage0002.checksum = 0x7e;
//                        jkMessage0002.checksum = 0x7e;
                        MessageProcessor.getInstance().sendMessage(jkMessage0002);
                        Log.i(TAG, "run: 5s一次");
                    }
app/src/main/java/safeluck/drive/evaluation/im/IMSClientBootstrap.java
@@ -107,4 +107,10 @@
            imsClient.sendMsg(message);
        }
    }
    public void addHeartbeat(int seconds){
        if (isActive){
            imsClient.addHeartbeatHandler(seconds);
        }
    }
}
app/src/main/java/safeluck/drive/evaluation/im/IMSEventListener.java
@@ -2,6 +2,9 @@
import com.anyun.im_lib.listener.OnEventListener;
import safeluck.drive.evaluation.platformMessage.JKMessage0002;
import safeluck.drive.evaluation.platformMessage.utils.MessageEscaper;
/**
 * MyApplication2
 * Created by lzw on 2019/12/12. 16:12:40
@@ -12,10 +15,11 @@
    private String userId;
    private String token;
    private MessageEscaper messageEscaper;
    public IMSEventListener(String userId, String token) {
        this.userId = userId;
        this.token = token;
        messageEscaper = new MessageEscaper();
    }
    @Override
@@ -71,4 +75,10 @@
    public byte[] getRegisterMessage() {
        return null;
    }
    @Override
    public byte[] getHearbeatMsg() {
        JKMessage0002 jkMessage0002 = new JKMessage0002();
        return messageEscaper.escape(jkMessage0002.toBytes());
    }
}
app/src/main/java/safeluck/drive/evaluation/im/IMessageProcessor.java
@@ -11,4 +11,6 @@
public interface IMessageProcessor {
    void receiveMsg(byte[] message);
    void sendMessage(JK2019MessageBase msg);
    void addBeatHeart(int seconds);
}
app/src/main/java/safeluck/drive/evaluation/im/MessageProcessor.java
@@ -8,6 +8,7 @@
import androidx.work.WorkManager;
import com.anyun.exam.lib.MyLog;
import com.anyun.im_lib.interf.IMSClientInteface;
import com.anyun.im_lib.util.ByteUtil;
import com.google.gson.Gson;
import com.safeluck.aykj.utils.BytesUtils;
@@ -105,4 +106,11 @@
            }
        });
    }
    @Override
    public void addBeatHeart(int seconds) {
        if (IMSClientBootstrap.getInstance().isActive()){
            IMSClientBootstrap.getInstance().addHeartbeat(seconds);
        }
    }
}
im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java
@@ -1,6 +1,13 @@
package com.anyun.im_lib;
import com.anyun.im_lib.netty.NettyTcpClient;
import com.anyun.im_lib.util.MyLog;
import com.safeluck.aykj.utils.BytesUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
/**
 * MyApplication2
@@ -9,4 +16,50 @@
 * All Rights Saved! Chongqing AnYun Tech co. LTD
 */
public class HeartbeatHandler extends ChannelInboundHandlerAdapter  {
    private NettyTcpClient imsClient;
    public HeartbeatHandler(NettyTcpClient imsClient) {
        this.imsClient = imsClient;
    }
    private HeartbeatTask heartbeatTask;
    private class HeartbeatTask implements Runnable {
        private ChannelHandlerContext ctx;
        public HeartbeatTask(ChannelHandlerContext ctx) {
            this.ctx = ctx;
        }
        @Override
        public void run() {
            if (ctx.channel().isActive()) {
                byte []heartbeatMsg = imsClient.getHeartbeatMsg();
                if (heartbeatMsg == null) {
                    return;
                }
                MyLog.i("发送心跳消息,message=" +  BytesUtils.bytesToHexString(heartbeatMsg) + "当前心跳间隔为:" +imsClient.getHeartbeatInterval() + "ms\n");
                imsClient.sendMsg(heartbeatMsg, false);
            }
        }
    }
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
        if (evt instanceof IdleStateEvent){
            IdleState state = ((IdleStateEvent)evt).state();
            MyLog.i("Netty TCP Idlestate="+state.name());
            switch (state){
                case READER_IDLE:
                    // 规定时间内没收到服务端心跳包响应,进行重连操作
                    break;
                case WRITER_IDLE:
                    // 规定时间内没向服务端发送心跳包,即发送一个心跳包
                    if (heartbeatTask == null) {
                        heartbeatTask = new HeartbeatTask(ctx);
                    }
                    imsClient.getLoopGroup().execWorkTask(heartbeatTask);
                    break;
            }
        }
    }
}
im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java
@@ -10,7 +10,7 @@
    public static final int CONNECT_STATE_FAILURE = -1;
    public static final int DEFAULT_RECONNECT_BASE_DELAY_TIME = 3 * 1000;
    public static final int DEFAULT_CONNECT_TIMEOUT = 10 * 1000;
    public static final int DEFAULT_HEARTBEAT_INTERVAL_FOREGROUND = 3 * 1000;
    public static final int DEFAULT_HEARTBEAT_INTERVAL_FOREGROUND = 10 * 1000;
    public static final int DEFAULT_HEARTBEAT_INTERVAL_BACKGROUND = 30 * 1000;
    /*** 应用在前台标识***/
im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java
@@ -112,4 +112,8 @@
//获取注册消息
    byte[] getRegisterMessage();
    byte[] getHeartbeatMsg();
    void addHeartbeatHandler(int seconds);
}
im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java
@@ -59,4 +59,6 @@
    int getReConnectInterval();
//注册消息
    byte[] getRegisterMessage();
    byte[] getHearbeatMsg();
}
im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java
@@ -17,6 +17,7 @@
import java.nio.ByteBuffer;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import java.util.function.ToDoubleBiFunction;
import io.netty.bootstrap.Bootstrap;
@@ -405,6 +406,34 @@
        return null;
    }
    @Override
    public byte[] getHeartbeatMsg() {
        if (mOnEventListener != null){
            return mOnEventListener.getHearbeatMsg();
        }
        return null;
    }
    /**
     * 增加心跳,
     * @param heartBeatInterval 秒
     */
    @Override
    public void addHeartbeatHandler(int heartBeatInterval){
        this.heartBeatInterval = heartBeatInterval*1000;
        _addHeartbeatHandler();
    }
    public int getHeartbeatInterval() {
        return this.heartBeatInterval;
    }
    public ExecutorServiceFactory getLoopGroup() {
        return loopGroup;
    }
    /**
     * 重连任务
@@ -522,6 +551,37 @@
    }
    private void _addHeartbeatHandler(){
        MyLog.i("add HeartbeatHandler");
        if (channel == null || !channel.isActive() || channel.pipeline()==null){
            MyLog.i("PlatformMessage","添加心跳handler失败");
            return;
        }
        try {
            if(channel.pipeline().get(IdleStateHandler.class.getSimpleName()) != null){
                MyLog.i("PlatformMessage","之前存在的读写超时handler,先移除掉,再重新添加");
                channel.pipeline().remove(IdleStateHandler.class.getSimpleName());
            }
            // 3次心跳没响应,代表连接已断开
            //设定IdleStateHandler心跳检测每四秒进行一次写检测,如果四秒内write()方法未被调用则触发一次userEventTrigger()方法,实现客户端每四秒向服务端发送一次消息;
            channel.pipeline().addFirst(IdleStateHandler.class.getSimpleName(), new IdleStateHandler(
                    0, heartBeatInterval, 0, TimeUnit.MILLISECONDS));
            // 重新添加HeartbeatHandler
            if (channel.pipeline().get(HeartbeatHandler.class.getSimpleName()) != null) {
                channel.pipeline().remove(HeartbeatHandler.class.getSimpleName());
            }
            if (channel.pipeline().get(TCPReadHandler.class.getSimpleName()) != null) {
                MyLog.i("之前存在的先移除掉,再重新添加HeartbeatHandler");
                channel.pipeline().addBefore(TCPReadHandler.class.getSimpleName(), HeartbeatHandler.class.getSimpleName(),
                        new HeartbeatHandler(this));
            }
        } catch (Exception e) {
            e.printStackTrace();
            MyLog.i("添加心跳消息管理handler失败,reason:" + e.getMessage());
        }
    }
}
im_lib/src/main/java/com/safeluck/aykj/message/BinMessageBase.java
@@ -168,7 +168,7 @@
            try {
                Object value = fieldDefine.field.get(this);
                String hex = fieldDefine.coder.encode(value);
                Log.i("PlatformMessage", "FieldName: "+fieldDefine.field.getName()+" hex:"+hex);
//                Log.i("PlatformMessage", "FieldName: "+fieldDefine.field.getName()+" hex:"+hex);
                if (hex == null) {
                    fieldDefine.relativeLengthField.set(this, 0);
                } else {
@@ -211,8 +211,7 @@
                        hex = this.getPaddingLeftString(hex,fieldDefine.getFieldLen()*2, BytesUtils.toHexString(fieldDefine.length.paddingByte()));
                    }
                }
//                System.out.println(hex);
                Log.i("PlatformMessage value", "FieldName: "+fieldDefine.field.getName()+" hex:"+hex);
//                Log.i("PlatformMessage value", "FieldName: "+fieldDefine.field.getName()+" hex:"+hex);
                sb.append(hex);
            } catch (IllegalAccessException e) {
                this.buildException(e.getMessage());