package com.flightfeather.obd.socket
|
|
import io.netty.buffer.ByteBuf
|
import io.netty.channel.ChannelHandlerContext
|
import io.netty.handler.codec.ByteToMessageDecoder
|
import java.lang.StringBuilder
|
|
/**
|
* @author riku
|
* Date: 2019/9/16
|
* 数据粘包分包解码器
|
*/
|
class ObdByteDataDecoder : ByteToMessageDecoder() {
|
|
companion object {
|
const val BASE_LENGTH = 2 + 1 + 17 + 1 + 1 + 2 + 0 + 1
|
const val HEAD = 0x23.toByte()
|
}
|
|
override fun decode(p0: ChannelHandlerContext?, p1: ByteBuf?, p2: MutableList<Any>?) {
|
|
val dataList = mutableListOf<Byte>()
|
|
p1?.let {
|
// 可读长度必须大于基本长度
|
if (it.readableBytes() >= BASE_LENGTH) {
|
// 防止socket字节流攻击
|
// 防止,客户端传来的数据过大
|
if (it.readableBytes() > 2048) {
|
it.skipBytes(it.readableBytes())
|
}
|
// 记录包头开始的index
|
var beginReader = 0
|
|
while (true) {
|
// 获取包头开始的index
|
beginReader = it.readerIndex()
|
// 标记包头开始的index
|
it.markReaderIndex()
|
// 读到了协议的开始标志,结束while循环
|
val b = ByteArray(2)
|
it.readBytes(b)
|
if (b[0] == HEAD && b[1] == HEAD) {
|
dataList.add(b[0])
|
dataList.add(b[1])
|
break
|
}
|
|
// 未读到包头,重置到之前记录的包头开始位置
|
// 略过1个字节后,再循环开始读取
|
it.resetReaderIndex()
|
it.readByte()
|
|
//当数据包长度不足时,立刻结束,等待后续数据到达
|
if (it.readableBytes() < BASE_LENGTH) {
|
return
|
}
|
}
|
|
ByteArray(1 + 17 + 1 + 1).apply {
|
it.readBytes(this)
|
}.forEach {b ->
|
dataList.add(b)
|
}
|
|
//数据单元的长度
|
val length = getDataUnitLength(it, dataList)
|
// 判断请求数据单元数据及1个字节的校验码是否到齐
|
if (it.readableBytes() < length + 1) {
|
// 还原读指针
|
it.readerIndex(beginReader)
|
return
|
}
|
|
//读取数据单元和校验码数据
|
ByteArray(length + 1).apply {
|
it.readBytes(this)
|
}.forEach {b ->
|
dataList.add(b)
|
}
|
|
p2?.add(dataList.toByteArray())
|
|
}
|
}
|
}
|
|
/**
|
* 获取数据单元长度并将其添加至结果列表中
|
*/
|
private fun getDataUnitLength(p1: ByteBuf, dataList: MutableList<Byte>): Int {
|
val sb = StringBuilder()
|
|
ByteArray(2).apply {
|
p1.readBytes(this)
|
}.forEach { b ->
|
var a = 0
|
a = if (b < 0) {
|
b + 256
|
} else {
|
b.toInt()
|
}
|
|
sb.append(a.toString(16))
|
|
dataList.add(b)
|
}
|
|
return sb.toString().toInt(16)
|
}
|
|
}
|