本文主要是介绍netty 809协议,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
netty 809协议
- 目录
- 概述
- 需求:
- 设计思路
- 实现思路分析
- 1.netty 809 协议
- 2.概念
- 代码
- 参考资料和推荐阅读
Survive by day and develop by night.
talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for change,challenge Survive.
happy for hardess to solve denpendies.
目录
概述
netty 809协议
需求:
netty 809协议
设计思路
实现思路分析
1.netty 809 协议
2.概念
1.先一个数据头,
消息体内容是: 对应的byte 位的了。
我们来看一下message 包体的内容。看下是如何组件的?
组装的时候套上对应的数据头,数据体,CRC,报文头尾等。
在这里组装对应的信息,配置上对应的报文头,数据体,CRC,报文尾就可以发送了。
内部传输的是十六进制2二进制数据。
判断的时候是根据十六进制判断。
转成2进制,对byte 位进行判断。 打包发送。
这个vo 貌似就没有用到。
将重要信息转成二进制数据即可。
组装这个messsageBody.会将vo 去掉。
这是因为java中的byte是有符号位的byte,
这点和c++不一样,因此可表示的数据为-127~127(最高位为符号位)。
知道了原因,剩下的就是问题的解决了。
服务端:
1.服务端接收以后,在计算机中bytes 传送的,首先将接收到数据包转成对应的16进制,
2.检测是有否转义含义
3.最后解析部分数据:
代码
package cn.com.onlinetool.jt809.decoder;import cn.com.onlinetool.jt809.constants.JT809MessageConstants;
import cn.com.onlinetool.jt809.decoderDemo.JT809Packet0x1202Decoder;
import cn.com.onlinetool.jt809.util.ByteArrayUtil;
import cn.com.onlinetool.jt809.util.PacketUtil;
import cn.com.onlinetool.jt809.util.ParseUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;/*** @author choice* @description: 消息解码* @date 2018-12-27 14:39*/
@Slf4j
@Service
public class Byte2MessageDecoder {private static Map<String, byte[]> cache = new HashMap<String, byte[]>();public void decode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {String channelKey = ctx.channel().remoteAddress().toString();//判断是否有可读的字节if (msg.readableBytes() <= 0) {return;}//读取缓冲区数据byte[] readDatas = new byte[msg.readableBytes()];msg.readBytes(readDatas);log.info("接收到数据包, packetLen : {}, packet : {}", readDatas.length, ByteArrayUtil.bytes2HexStr(readDatas));//拼接缓存数据byte[] cacheDatas = cache.get(channelKey);if (null != cacheDatas) {readDatas = ByteArrayUtil.append(cacheDatas, readDatas);cache.remove(channelKey);log.info("拼接后的数据包:{}", ByteArrayUtil.bytes2HexStr(readDatas));}//校验数据头
// if (!PacketUtil.checkHeadFlag(readDatas)) {
// //防止极端情况,请求头校验不通过的情况 丢掉本包数据 同时 丢掉上一包缓存的剩余数据
// //防止上一包剩余数据不包含数据起始符 会导致拼接后的数据包一直校验不通过
// cache.remove(channelKey);
// log.warn("数据包标识符验证失败 : {}", ByteArrayUtil.bytes2HexStr(readDatas));
// return;
// }//数据转义String dataStr = ByteArrayUtil.bytes2FullHexStr(readDatas);dataStr = dataStr.replaceAll("0x5a0x01", "0x5b");dataStr = dataStr.replaceAll("0x5a0x02", "0x5a");dataStr = dataStr.replaceAll("0x5e0x01", "0x5d");dataStr = dataStr.replaceAll("0x5e0x02", "0x5e");readDatas = ByteArrayUtil.fullHexStr2Bytes(dataStr);log.info("转义后的数据包:{}", ByteArrayUtil.bytes2HexStr(readDatas));//如果数据小于一整包数据的最小长度
// if (readDatas.length < JT809MessageConstants.MSG_MIN_LEN) {
// log.warn("数据长度小于整包数据最小长度,缓存数据:{}", ByteArrayUtil.bytes2HexStr(readDatas));
// cache.put(channelKey, readDatas);
// return;
// }
//
// //判断是否有完整数据包,没有直接缓存
// int packetLen = PacketUtil.getPacketLen(readDatas);
// if (readDatas.length < packetLen) {
// log.warn("数据长度小于整包数据长度,缓存数据:{}", ByteArrayUtil.bytes2HexStr(readDatas));
// cache.put(channelKey, readDatas);
// return;
// }//解析数据this.parseAndPushData(ctx, channelKey, 0, readDatas);}/*** 解析并返回数据** @param channelKey* @param readDatas*/private void parseAndPushData(ChannelHandlerContext ctx, String channelKey, int index, byte[] readDatas) throws Exception {byte[] data = ByteArrayUtil.subBytes(readDatas, index, readDatas.length - index);// //整包长度
// int packetLen = PacketUtil.getPacketLen(data);
// index += packetLen;
//
// //一个完整包
// byte[] fullPacket = ByteArrayUtil.subBytes(data, 0, packetLen);
// log.info("拆包后的单包数据 --> fullPacket : {}", ByteArrayUtil.bytes2HexStr(fullPacket));log.info("拆包后的单包数据 --> fullPacket : {}", ByteArrayUtil.bytes2HexStr(data));// //验证数据包有效性
// if (!PacketUtil.checkPacket(fullPacket)) {
// cache.remove(channelKey);
// log.info("数据校验失败 --> fullPacket : {}", ByteArrayUtil.bytes2HexStr(fullPacket));
// return;
// }
// ctx.fireChannelRead(PacketUtil.bytes2Message(fullPacket));
//
// //剩余长度
// int remainingLen = data.length - packetLen;//没有数据,结束
// if (remainingLen < 1) {
// return;
// }
//
// //剩余数据长度小于一包数据的最小长度,缓存数据
// if (remainingLen < JT809MessageConstants.MSG_MIN_LEN) {
// log.warn("剩余数据长度小于整包数据最小长度,缓存数据:{}", ByteArrayUtil.bytes2HexStr(ByteArrayUtil.subBytes(data, data.length - remainingLen, remainingLen)));
// cache.put(channelKey, ByteArrayUtil.subBytes(data, data.length - remainingLen, remainingLen));
// return;
// }
//
// //下一包数据的总长度
// packetLen = PacketUtil.getPacketLen(ByteArrayUtil.subBytes(data,data.length - remainingLen, remainingLen));
// //剩余数据长度小于整包数据长度
// if (remainingLen < packetLen) {
// log.warn("剩余数据长度小于整包数据长度,缓存数据:{}", ByteArrayUtil.bytes2HexStr(ByteArrayUtil.subBytes(data, data.length - remainingLen, remainingLen)));
// cache.put(channelKey, ByteArrayUtil.subBytes(data, data.length - remainingLen, remainingLen));
// return;
// }//还有完整数据包 递归调用
// this.parseAndPushData(ctx, channelKey, index, readDatas);JT809Packet0x1202Decoder jt809Packet0x1202Decoder=new JT809Packet0x1202Decoder();jt809Packet0x1202Decoder.decoder(data);
// parsePkt(data);}private void parsePkt(byte[] data) {// begin 这里提供方法可供入库使用,根据不同的业务进行字段分段截取.默认解析字段分别是业务字段的含义字段String parseData = ByteArrayUtil.bytes2HexStr(data);//比如这里增加子业务类型的字段数据:if(StringUtil.isNullOrEmpty(parseData)){log.info("数据为空");return;}else {//数据头String head = parseData.substring(0, 2); //--头标识String datalength=parseData.substring(2,10);//--数据头->数据长度String dataSeqNo=parseData.substring(10,18);// --数据头->报文序列号String bizdata=parseData.substring(18,22);// --数据头->业务数据类型String code=parseData.substring(22,30); //--数据头->下级平台接入码,上级平台给下级平台分配唯一标识码String version=parseData.substring(30,36); //--数据头->协议版本号标识String entryFlag=parseData.substring(36,38);//--数据头->报文加密标识位String key=parseData.substring(38,46);//--数据头->数据加密的密匙//数据体
// String chepaiHao=parseData.substring(46,50);// --数据体->车牌号
// String color=parseData.substring(50,52); // --数据体->车辆颜色 //这2者没有String biz =parseData.substring(46,50); //--数据体->子业务类型标识String lastlength=parseData.substring(50,58);//--数据体->后续数据长度,这里的确是24 位 ,数据长度24位//子数据体String subData=parseData.substring(58,82); //参看4.5.8.1 车辆定位信息数据体//3.CRCString crc=parseData.substring(82,86); //这个每次都变化的String tail=parseData.substring(86,88);//2.业务数据体这里调用Parse方法,可以封装对应的实体bean,供入库用,提供int ,varchar,time 三种格式进行
// log.info("总长度是:{}"+subData);}//end}
}
解包代码:
package cn.com.onlinetool.jt809.decoderDemo;import cn.com.onlinetool.jt809.jt.Decoder;
import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.nio.charset.Charset;
import java.time.LocalDate;
import java.time.LocalTime;/*** @Author: Xiuming Lee* @Date: 2019/9/23 15:21* @Version 1.0* @Describe:*/
public class JT809Packet0x1202Decoder {private static Logger log = LoggerFactory.getLogger(JT809Packet0x1202Decoder.class);public JT809BasePacket decoder(byte[] bytes) throws Exception {JT809Packet0x1202 jt809Packet0x1202 = new JT809Packet0x1202();ByteBuf byteBuf = PacketDecoderUtils.baseDecoder(bytes, jt809Packet0x1202);packetDecoder(byteBuf,jt809Packet0x1202);return jt809Packet0x1202;}private void packetDecoder(ByteBuf byteBuf, JT809Packet0x1202 packet) throws Exception{ByteBuf msgBodyBuf = null;if (packet.getEncryptFlag() == Const.EncryptFlag.NO) {msgBodyBuf = PacketDecoderUtils.getMsgBodyBuf(byteBuf);} else {msgBodyBuf = null;return;}// 车牌号byte [] vehicleNoBytes = new byte[21];msgBodyBuf.readBytes(vehicleNoBytes);packet.setVehicleNo(new String(vehicleNoBytes, Charset.forName("utf-8")));// 车辆颜色packet.setVehicleColor(msgBodyBuf.readByte());// 子业务类型标识packet.setDataType(msgBodyBuf.readShort());// 如果不是定位的数据,抛出空指针错误,解码适配器会对空指针错误做处理。
// if (packet.getDataType() != Const.SubBusinessDataType.UP_EXG_MSG_REAL_LOCATION ) {
// throw new NullPointerException();
// }// 后续数据长度packet.setDataLength(msgBodyBuf.readInt());// 经纬度信息是否按国标进行加密packet.setExcrypt(msgBodyBuf.readByte());if (packet.getExcrypt() == Const.EncryptFlag.YES ){}// 跳过时间
// msgBodyBuf.skipBytes(7);int day = Byte.toUnsignedInt(msgBodyBuf.readByte());int month = Byte.toUnsignedInt(msgBodyBuf.readByte());
// packet.setDate(LocalDate.of(msgBodyBuf.readShort(),month,day));
// packet.setTime(LocalTime.of(Byte.toUnsignedInt(msgBodyBuf.readByte()),Byte.toUnsignedInt(msgBodyBuf.readByte()),Byte.toUnsignedInt(msgBodyBuf.readByte())));// 经纬度packet.setLon(msgBodyBuf.readInt());packet.setLat(msgBodyBuf.readInt());// 速度packet.setVec1(msgBodyBuf.readShort());// 行驶记录速度packet.setVec2(msgBodyBuf.readShort());// 车辆当前总里程数
// packet.setVec3(msgBodyBuf.readInt());
// // 方向
// packet.setDirection(msgBodyBuf.readShort());
// // 海拔
// packet.setAltitude(msgBodyBuf.readShort());
// // 车辆状态
// packet.setState(msgBodyBuf.readInt());
// // 报警状态
// packet.setAlarm(msgBodyBuf.readInt());}}
参考资料和推荐阅读
- 暂无
欢迎阅读,各位老铁,如果对你有帮助,点个赞加个关注呗!同时,期望各位大佬的批评指正~
这篇关于netty 809协议的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!