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

相关文章

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协议的相关知识,但是在传输层,还有

DNS协议基础笔记

1.定义 DNS(Domain Name System,域名系统)是互联网的一项核心服务,它作为将域名和 IP 地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。 2.域名解析过程 当用户在浏览器中输入一个域名,浏览器首先会检查自己的缓存中是否有该域名对应的 IP 地址。本地 DNS 服务器收到查询请求后,首先会检查自己的缓存中是否有该域名对应的 IP 地址。根域名服务器收到查询请

4G模块、WIFI模块、NBIOT模块通过AT指令连接华为云物联网服务器(MQTT协议)

MQTT协议概述 MQTT(Message Queuing Telemetry Transport)是一种轻量级的消息传输协议,它被设计用来提供一对多的消息分发和应用之间的通讯,尤其适用于远程位置的设备和高延迟或低带宽的网络。MQTT协议基于客户端-服务器架构,客户端可以订阅任意数量的主题,并可以发布消息到这些主题。服务器(通常称为MQTT Broker)则负责接受来自客户端的连接请求,并转发消

HTTP协议 HTTPS协议 MQTT协议介绍

目录 一.HTTP协议 1. HTTP 协议介绍 基本介绍: 协议:  注意: 2. HTTP 协议的工作过程 基础术语: 客户端: 主动发起网络请求的一端 服务器: 被动接收网络请求的一端 请求: 客户端给服务器发送的数据 响应: 服务器给客户端返回的数据 HTTP 协议的重要特点: 一发一收,一问一答 注意: 网络编程中,除了一发一收之外,还有其它的模式 二.HTT

CAMediaTiming协议

今天看下下CALayer这个类,里面的属性是实现CAMediaTiming这个协议的,这里简单介绍一下CAMediaTiming协议里面的属性。官网链接 如下 beginTime:开始时间(和父类相关) timeOffset:动态的本地时间t,tp是父类事件。t = (tp - begin) * speed + offset.用于暂停一个layer。  fillMode:layer完成后的