先看一下JT808數據的組成和OkSocket接收消息方式;
1、JT808數據的組成
標識位採用0x7e 表示,若校驗碼、消息頭以及消息體中出現0x7e,則要進行轉義處理,轉義規則定義如下:0x7e <————> 0x7d後緊跟一個0x02;0x7d <————> 0x7d後緊跟一個0x01。轉義處理過程 如下:發送消息時:消息封裝——>計算並填充校驗碼——>轉義;接收消息時:轉義還原——>驗證校驗碼——>解析消息。示例:發送一包內容爲:0x3 00x7e 0x08 0x7d 0x55的數據包,則經過封裝如下:0x7e 0x30 7d 0x02 0x08 0x7d 0x01 0x55 0x7e。
2、OkSocket接收消息方式:
注意:
Header
:指的是數據協議中定長部分,該部分應該包含後面不定長的Body(Payload)的字節長度.Body(Payload)
:指的是不定長部分,通常是數據區:
出現的問題:
我以爲使用OkSocket實現JT808協議通訊這種方法是完美的,直到我頻繁遇到這種數據(數據包②沒有尾部標識位):
①、7E 80 01 00 05 01 56 51 82 18 22 00 7B 00 7C 00 02 00 4F 7E
②、7E 80 01 00 05 01 56 51 82 18 22 00 7C 00 7D 01 02 00 00 49
數據②中沒有尾部標識位7E,我告訴後臺應答的數據不全,後臺檢查後說沒有問題,而且IOS端也沒有出現該問題;
檢查數據後發現數據②中有一個"7D 01"數據,該數據按照轉義規則是由 "7E"轉義後的,所以本來佔一個Byte位 "7E"變成了佔兩個Byte位的"7D 01",根據OkSocket的規則(固定消息頭,從消息頭中獲取消息體的長度)所以沒有獲取到最後的標識位;
正想通知後臺把從消息頭中獲取消息體的長度改爲轉義後的,想到消息頭中的數據包可能被轉義,所以轉義後的消息頭就變爲不固定長度的了;
按照JT808的數據組成規則,消息頭的長度不是固定的;則不能使用OkSocket的接收方式;
解決方法:
重寫OkSocket數據包接收方式OkSocket接收所有數據,可以不固定協議頭:
//接收byte數組
@Override
public void read() throws RuntimeException {
OriginalData originalData = new OriginalData();
try {
InputStream is = mInputStream;
DataInputStream input = new DataInputStream(is);
byte[] b = new byte[1024 * 1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = 0;
while (true) {
len = input.read(b);
bos.write(b, 0, len);
originalData.setBodyBytes(bos.toByteArray());
mStateSender.sendBroadcast(IOAction.ACTION_READ_COMPLETE, originalData);
bos.reset();
}
} catch (Exception e) {
ReadException readException = new ReadException(e);
throw readException;
}
}
把數據包全部放在消息體中:
@Override
public void onSocketReadResponse(ConnectionInfo info, String action, OriginalData data) {
byte[] body = data.getBodyBytes(); //原數據
}
這樣就可以拿到全部的數據了,但是沒有了從消息頭確定消息尾的長度功能後,有可能會出現粘包的情況 Socket 粘包 拆包;