前言:
以下是我踩過的一個坑,文章的思路和方法還是對的,但是不適合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;
}
}