Android OkSocket设置消息头,获取消息体长度;使用OkSocket实现JT808协议通讯;

前言:

以下是我踩过的一个坑,文章的思路和方法还是对的,但是不适合JT808协议,更新了一版:JT808协议通讯,使用OkSocket实现长连接

OkSocket设置消息头,获取消息体长度

本文章只讲如何使用OkSocket接收JT808消息 ,如何设置解析头和从消息头中获取消息体长度;

查看Android JT808协议通讯请移步;

以下是OkSocket设置消息头和从消息头中获取消息体长度:

OkSocket需要设置解析头,如下:

//设置自定义解析头
OkSocketOptions.Builder okOptionsBuilder = new OkSocketOptions.Builder(mOkOptions);
okOptionsBuilder.setReaderProtocol(new IReaderProtocol() {
    @Override
    public int getHeaderLength() {
        / *
         * 返回不能为零或负数的报文头长度(字节数)。
         * 您返回的值应符合服务器文档中的报文头的固定长度值(字节数),可能需要与后台同学商定
         * /
        return / *固定报文头的长度(字节数)* /;
    }

    @Override
    public int getBodyLength(byte[] header, ByteOrder byteOrder) {
     / *
         * 体长也称为有效载荷长度,
         * 该值应从作为函数输入参数的header中读取。
         * 从报文头数据header中解析有效负载长度时,最好注意参数中的byteOrder。
         * 我们强烈建议您使用java.nio.ByteBuffer来做到这一点。
         * 你需要返回有效载荷的长度,并且返回的长度中不应该包含报文头的固定长度
         * /
        return /*有效负载长度(字节数),固定报文头长度(字节数)除外*/;
    }
});
//将新的修改后的参配设置给连接管理器
mManager.option(okOptionsBuilder.build());

而JT808得消息头中就有消息体的长度;

当时跟服务器约定好,"消息包封装项"没有数据时返回0即可; 可以确定消息头的长度是13;

拿到消息头后开始计算消息体的长度:

public class JT808ReaderProtocol implements IReaderProtocol {
    @Override
    public int getHeaderLength() {
        return 13;
    }

    @Override
    public int getBodyLength(byte[] header, ByteOrder byteOrder) {
        //去除0X7E
        byte[] del7eBytes = Arrays.copyOfRange(header, 1, header.length);
        // 把JT808数据头解析成为实体
        Header808Bean header808 = JTT808Coding.resolve808ToHeader(del7eBytes);
        // 从消息头实体中获取消息体长度+2(检验码、包尾0X7E
        return header808.getBodyAttr().getBodyLength() + 2;
    }
}

把消息头中的数据转为实体类:

/**
     * 解析808数据解析成实体类
     *
     * @param bytes 去除了7E的数据
     *              eg:80 01 00 05 04 00 45 50 34 32 00 00 00 00 01 02 00
     * @return
     */
    public static Header808Bean resolve808ToHeader(byte[] bytes) {
        Header808Bean header808 = new Header808Bean();
        byte[] msgId = Arrays.copyOfRange(bytes, 0, 2);
        byte[] msgBodyAttributes = Arrays.copyOfRange(bytes, 2, 4);
        byte[] phone = Arrays.copyOfRange(bytes, 4, 10);
        byte[] msgFlowNum = Arrays.copyOfRange(bytes, 10, 12);

        header808.setMsgID(ByteUtil.bytes2Int(msgId));
        header808.setMobile(HexUtil.byte2HexStrNoSpace(phone));
        header808.setSeqNO(ByteUtil.bytes2Int(msgFlowNum));
        Header808Bean.BodyAttrBean  bodyAttrBean = new Header808Bean.BodyAttrBean();
        bodyAttrBean.setBodyLength(BitOperator.msgHeaderGetBodyLength(msgBodyAttributes)); //获取消息体长度
        String bodyAtteBit = ByteUtil.byteToBit(msgBodyAttributes[0]); //取到前8位
        bodyAttrBean.setEncrypt(!"000".equals(bodyAtteBit.substring(3,6))); //获取是否加密位
        bodyAttrBean.setSplit(!"0".equals(bodyAtteBit.substring(2,3))); //获取是否分包位
        header808.setBodyAttr(bodyAttrBean);
        return header808;
    }
    /**
     * Jt808消息头属性获取消息体长度
     *  @param bytes 消息头属性  长度是2的byte数组
     */
    public static int msgHeaderGetBodyLength(byte[] bytes) {
        //把数组转为Bit
        String property = ByteUtil.byteToBit(bytes[0]) + ByteUtil.byteToBit(bytes[1]);
        //bit删除前6位,从第7位开始截取
        String msgL = property.substring(6);
        //bit转Int
        int msgLInt = Integer.parseInt(msgL, 2);
        return msgLInt;
    }

实体类:

public class Header808Bean {

    /**
     * mobile : 00000000
     * msgID : 2
     * bodyAttr : {"split":false,"encrypt":false,"bodyLength":0}
     * seqNO : 1
     */

    public String mobile;
    public int msgID;
    public BodyAttrBean bodyAttr;
    public int seqNO;

    public static class BodyAttrBean {
        public boolean split;
        public boolean encrypt;
        public int bodyLength;
    }
    
}

源码:https://github.com/CuiChenbo/JT808_OkSocket

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章