前言:
以下是我踩过的一个坑,文章的思路和方法还是对的,但是不适合JT808协议,更新了一版:JT808协议通讯,使用OkSocket实现长连接
OkSocket设置消息头,获取消息体长度
本文章只讲如何使用OkSocket接收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;
}
}