netty 809协议

2023-10-18 22:10
文章标签 协议 netty 809

本文主要是介绍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());}}

参考资料和推荐阅读

  1. 暂无

欢迎阅读,各位老铁,如果对你有帮助,点个赞加个关注呗!同时,期望各位大佬的批评指正~

这篇关于netty 809协议的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/235420

相关文章

Nginx中配置HTTP/2协议的详细指南

《Nginx中配置HTTP/2协议的详细指南》HTTP/2是HTTP协议的下一代版本,旨在提高性能、减少延迟并优化现代网络环境中的通信效率,本文将为大家介绍Nginx配置HTTP/2协议想详细步骤,需... 目录一、HTTP/2 协议概述1.HTTP/22. HTTP/2 的核心特性3. HTTP/2 的优

关于WebSocket协议状态码解析

《关于WebSocket协议状态码解析》:本文主要介绍关于WebSocket协议状态码的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录WebSocket协议状态码解析1. 引言2. WebSocket协议状态码概述3. WebSocket协议状态码详解3

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

Qt 中集成mqtt协议的使用方法

《Qt中集成mqtt协议的使用方法》文章介绍了如何在工程中引入qmqtt库,并通过声明一个单例类来暴露订阅到的主题数据,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录一,引入qmqtt 库二,使用一,引入qmqtt 库我是将整个头文件/源文件都添加到了工程中进行编译,这样 跨平台

Java如何接收并解析HL7协议数据

《Java如何接收并解析HL7协议数据》文章主要介绍了HL7协议及其在医疗行业中的应用,详细描述了如何配置环境、接收和解析数据,以及与前端进行交互的实现方法,文章还分享了使用7Edit工具进行调试的经... 目录一、前言二、正文1、环境配置2、数据接收:HL7Monitor3、数据解析:HL7Busines

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

【Go】go连接clickhouse使用TCP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么                      🎵 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time""github.com/ClickHouse/clickhouse-go/v2")func main(

2024.9.8 TCP/IP协议学习笔记

1.所谓的层就是数据交换的深度,电脑点对点就是单层,物理层,加上集线器还是物理层,加上交换机就变成链路层了,有地址表,路由器就到了第三层网络层,每个端口都有一个mac地址 2.A 给 C 发数据包,怎么知道是否要通过路由器转发呢?答案:子网 3.将源 IP 与目的 IP 分别同这个子网掩码进行与运算****,相等则是在一个子网,不相等就是在不同子网 4.A 如何知道,哪个设备是路由器?答案:在 A

Modbus-RTU协议

一、协议概述 Modbus-RTU(Remote Terminal Unit)是一种基于主从架构的通信协议,采用二进制数据表示,消息中的每个8位字节含有两个4位十六进制字符。它主要通过RS-485、RS-232、RS-422等物理接口实现数据的传输,传输距离远、抗干扰能力强、通信效率高。 二、报文结构 一个标准的Modbus-RTU报文通常包含以下部分: 地址域:单个字节,表示从站设备

网络原理之TCP协议(万字详解!!!)

目录 前言 TCP协议段格式 TCP协议相关特性 1.确认应答 2.超时重传 3.连接管理(三次握手、四次挥手) 三次握手(建立TCP连接) 四次挥手(断开连接)  4.滑动窗口 5.流量控制 6.拥塞控制 7.延迟应答 8.捎带应答  9.基于字节流 10.异常情况的处理 小结  前言 在前面,我们已经讲解了有关UDP协议的相关知识,但是在传输层,还有