提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、实现netty采集jtt808协议
  • 二、使用步骤
    • 1.netty接入数据
    • 2.jtt808协议解析
      • 采用策略模式解析
      • 开始解析

提示:以下是本篇文章正文内容,下面案例可供参考

一、实现netty采集jtt808协议

二、使用步骤

1.netty接入数据

代码如下(示例):

 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.30.Final</version></dependency>

实现netty接入jtt808协议:

import com.qycloud.iot.microserviceindoorpositioning.gps.config.GpsConfiguration;
import com.qycloud.iot.microserviceindoorpositioning.netty.utils.GpsDecoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;@Component
@Slf4j
@Profile("!test1")  //单元测试类添加  @ActiveProfiles("test1")
public class NettyServer implements ApplicationRunner {@AutowiredGpsConfiguration gpsConfiguration;@AutowiredNettyServerHandler nettyServerHandler;@Overridepublic void run(ApplicationArguments args){// 创建对应的 线程池// 创建Boss groupEventLoopGroup boosGroup = new NioEventLoopGroup(1);// 创建 workgroupEventLoopGroup workGroup = new NioEventLoopGroup();// 创建对应的启动类ServerBootstrap bootstrap = new ServerBootstrap();try{// 设置相关的配置信息bootstrap.group(boosGroup,workGroup) // 设置对应的线程组.channel(NioServerSocketChannel.class) // 设置对应的通道.option(ChannelOption.SO_BACKLOG,1024) // 设置线程的连接个数.childHandler(new ChannelInitializer<SocketChannel>() { // 设置/*** 给pipeline 设置处理器*/@Overrideprotected void initChannel(SocketChannel socketChannel) {socketChannel.pipeline().addLast(new GpsDecoder());       //自定义的解码socketChannel.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));socketChannel.pipeline().addLast(nettyServerHandler);}});log.info("netty服务启动了....");// 绑定端口  启动服务ChannelFuture channelFuture = bootstrap.bind(gpsConfiguration.getPort()).sync();// 对关闭通道进行监听channelFuture.channel().closeFuture().sync();}catch (Exception e){log.error("netty启动错误....",e);}finally {// 优雅停服boosGroup.shutdownGracefully();workGroup.shutdownGracefully();}}
}

import com.qycloud.iot.microserviceindoorpositioning.gps.GpsProtocolDataHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
@ChannelHandler.Sharable
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {@AutowiredGpsProtocolDataHandler gpsProtocolDataHandler;/*** 读取客户端发送来的数据** @param ctx ChannelHandler的上下文对象 有管道 pipeline 通道 channel 和 请求地址 等信息* @param msg 客户端发送的具体数据*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {log.info("开始解析设备,拿到的数据为-------{}" ,msg);if (null == msg || msg.toString().isEmpty()) return;String body = (String) msg;gpsProtocolDataHandler.handleProtocol(ctx, body);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}@Overridepublic void channelRegistered(ChannelHandlerContext ctx) throws InterruptedException {//        SocketAddress address = ctx.channel().remoteAddress();
//        System.out.println("客户端请求到了..." + address);}@Overridepublic void channelUnregistered(ChannelHandlerContext ctx) throws Exception {//        SocketAddress address = ctx.channel().remoteAddress();
//        System.out.println("客户端请求断开..." + address);}/*** 读取客户端发送数据完成后的方法* 在本方法中可以发送返回的数据** @param ctx*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) {//        ctx.writeAndFlush(hexStrToBytes("ab13"));// writeAndFlush 是组合方法
//        ctx.channel().writeAndFlush(hexStrToBytes("ab13"));
//        ctx.writeAndFlush(Unpooled.copiedBuffer(rMsg,CharsetUtil.UTF_8));}}

netty解码,回写工具


import com.qycloud.iot.microserviceindoorpositioning.gps.utils.ByteUtils;
import com.qycloud.iot.microserviceindoorpositioning.gps.utils.GpsAnalyseUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;import java.util.List;
import java.util.Locale;/*** @Author: WangHao* @Date: 2021/10/19/16:47* @Description:*/
@Slf4j
public class GpsDecoder extends ByteToMessageDecoder {StringBuffer temp = new StringBuffer();@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {String HEXES = "0123456789ABCDEF";byte[] req = new byte[msg.readableBytes()];msg.readBytes(req);final StringBuilder hex = new StringBuilder(2 * req.length);for (int i = 0; i < req.length; i++) {byte b = req[i];hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))).append(" ");}
//        String content = decodeOri(hex.toString());String content = hex.toString().replace(" ", "");log.info("原始报文-------{}", content);StringBuffer realMsg = null;if (temp.length() > 0) {realMsg = new StringBuffer(temp);realMsg.append(content);log.info("合并:上一数据包余下的长度为:" + temp.length() + ",合并后长度为:" + realMsg.length());} else {realMsg = new StringBuffer(content);}String realMsgStr = realMsg.toString();//如果是  7E开头if (realMsgStr.startsWith("7E")) {if (realMsgStr.length()>50000){//找不到全部舍去temp = new StringBuffer();return;}dealStartWith7E(realMsgStr, out);} else {//查找第一个7E开头的int index7E = realMsgStr.indexOf("7E");if (index7E < 0) {//找不到全部舍去temp = new StringBuffer();return;}realMsgStr = realMsgStr.substring(index7E);dealStartWith7E(realMsgStr, out);}}private void dealStartWith7E(String realMsgStr, List<Object> out) {try {int index = realMsgStr.indexOf("7E", realMsgStr.indexOf("7E") + 1);if (index == -1) {temp = new StringBuffer(realMsgStr);
//                out.add("");return;}String data = realMsgStr.substring(0, index + 2);//data 必然为 7E开头,7E结尾boolean check = check(data);if (check) {out.add(decodeOri(data));String substring = realMsgStr.substring(data.length());//判断是否需要拆包if (substring.length() == 0) {temp = new StringBuffer();return;} else {dealStartWith7E(substring, out);return;}}String substring = realMsgStr.substring(index);dealStartWith7E(substring, out);}catch (Exception e){log.error("解析数据格式错误,数据为{},错误原因:{}",realMsgStr,e);}}//完整数据结构校验private boolean check(String data) {String decodeData = decodeOri(data);if (decodeData == null || decodeData.length() < 30 || !decodeData.toLowerCase(Locale.CHINA).startsWith("7e") || !decodeData.toLowerCase(Locale.CHINA).endsWith("7e")) {log.error("校验数据结构:数据{},错误原因:{}", decodeData, "数据不是以7E开头或者结尾,或者长度不满足最基础的30位");return false;}if (decodeData.length() < 26) {log.error("校验数据结构:数据{},错误原因:{}", decodeData, "数据头不正确,不满足26位");return false;}String bodySizeStr = decodeData.substring(6, 10);int bodySize = ByteUtils.hexStringToDec(bodySizeStr) * 2; //一个字节两位int contentSize = bodySize + 30;if (decodeData.length() < contentSize) {log.error("校验数据结构:数据{},错误原因:{}", decodeData, "消息体长度不正确");return false;}//验证校验位String headAndBody = decodeData.substring(2, 26 + bodySize);String check = decodeData.substring(bodySize + 26, bodySize + 26 + 2);String checkCode = GpsAnalyseUtils.createCheckCode(headAndBody);if (!check.equalsIgnoreCase(checkCode)) {log.error("校验数据结构:数据{},错误原因:{}", decodeData, "校验位不匹配");return false;}return true;}private static String decodeOri(String oriStr) {return oriStr.replaceAll("(?i)7D 02", "7E").replaceAll("(?i)7D 01", "7D").replace(" ", "");}public static void main(String[] args) {//        String realMsgStr = "7E07040342017028567195004B000A010055000000000000000001F0F61E06FD3D0F000000000000220521151419010400000000300114310100542405D46BA64B22BC32ECDA599807C12A54E061460D912890F7B225CEDB2690F7B226E83922E1014EEA0200010055000000000000000001F0F61E06FD3D0F000000000000220521151429010400000000300114310100542405D46BA64B22BC32ECDA599807C12A54E061460D912890F7B225CEDB2690F7B226E83922E1014EEA0200010055000000000000000001F0F61E06FD3D0F000000000000220521151439010400000000300114310100542405D46BA64B22BC32ECDA599807C12A54E061460D912890F7B225CEDB2690F7B226E83922E1014EEA0200010048000000000000000001F0F61E06FD3D0F0000000000002205211525200104000000003001173101009F173436302C30302C353533342C30383238323561302C3233E1014EEA0200010048000000000000000001F0F61E06FD3D0F0000000000002205211525300104000000003001173101009F173436302C30302C353533342C30383238323561302C3233E1014EEA0200010048000000000000000001F0F61E06FD3D0F0000000000002205211525400104000000003001173101009F173436302C30302C353533342C30383238323561302C3233E1014EEA0200010055000000000000000001F0F67E07040335017028567195004C000A010055000000000000000001F0F61E06FD3D0F000000000000220521152632010400000000300115310100542405ECDA599807C13454E061460D912A90F7B225CEDB2390F7B226E83923ECF8EB205F0923E1014EEA0200010055000000000000000001F0F61E06FD3D0F000000000000220521152642010400000000300115310100542405ECDA599807C13454E061460D912A90F7B225CEDB2390F7B226E83923ECF8EB205F0923E1014EEA0200010048000000000000000001F0F61E06FD3D0F0000000000002205211526520104000000003001153101009F173436302C30302C353533342C30383238323561302C3231E1014EEA0200010048000000000000000001F0F61E06FD3D0F0000000000002205211527020104000000003001153101009F173436302C30302C353533342C30383238323561302C3231E1014EEA0200010048000000000000000001F0F61E06FD3D0F0000000000002205211528220104000000003001133101009F173436302C30302C353533342C30383238323561302C3139E1014EEA0200010055000000000000000001F0F61E06FD3D0F000000000000220521152832010400000000300116310100542405ECDA599807C12A54E061460D9128ECF8EB205F092590F7B225CEDB2390F7B226E83921E1014EEA0200010055000000000000000001F0F61E06FD3D0F000000000000220521152953010400000000300113310100542405ECDA599807C13154E061460D912890F7B226E8392190F7B225CEDB20ECF8EB205F0920E1014EEA0200010055000000000000000001F0F61E06FD3D0F000000000000220521153003010400000000300113310100542405ECDA599807C13154E061460D912890F7B226E8392190F7B225CEDB20ECF8EB205F0920E1014EEA0200010055000000000000000001F0F61E06FD3D0F000000000000220521153014010400000000300113310100542405ECDA599807C13154E061460D912890F7B226E8392190F7B225CEDB20ECF8EB205F0920E1014EEA0200010048000000000000000001F0F61E06FD3D0F0000000000002205211530440104000000003001133101009F173436302C30302C353533342C30383238323561302C3139E1014EEA020001A97E";String realMsgStr = "7Esdfsdf7E";String data = "7Esdfsdf7E";String substring = realMsgStr.substring(data.length());System.out.println("substring:"+substring);String[] split = realMsgStr.split("7E07040E7E", 1);System.out.println(split);//        int i = realMsgStr.indexOf("7E", realMsgStr.indexOf("7E") + 1);
//
//        System.out.println(i);
//        String substring = realMsgStr.substring(realMsgStr.substring(2).indexOf("7E") + 2);
//        System.out.println(substring);}
}

import com.qycloud.iot.microserviceindoorpositioning.gps.utils.ByteUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;/*** @Author: WangHao* @Date: 2021/10/19/16:49* @Description:*/
@Slf4j
public class MyTools {private static volatile MyTools myTools;private MyTools() {}public static MyTools getInstance() {if (null == myTools) {synchronized (MyTools.class) {if (null == myTools) {myTools = new MyTools();}}}return myTools;}public void writeToClient(final String receiveStr, ChannelHandlerContext channel, final String mark) {try {ByteBuf bufff = Unpooled.buffer();//netty需要用ByteBuf传输bufff.writeBytes(ByteUtils.hexString2Bytes(receiveStr));//对接需要16进制channel.writeAndFlush(bufff).addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future) throws Exception {StringBuilder sb = new StringBuilder();if (null != mark && !mark.isEmpty()) {sb.append("【").append(mark).append("】");}if (future.isSuccess()) {log.debug(sb.toString() + "回写成功" + receiveStr);} else {log.warn(sb.toString() + "回写失败" + receiveStr);}}});} catch (Exception e) {e.printStackTrace();log.warn("调用通用writeToClient()异常" + e.getMessage());}}}

2.jtt808协议解析

采用策略模式解析

自定义注解


import com.qycloud.iot.microserviceindoorpositioning.gps.common.SignCode;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @Author: WangHao* @Date: 2021/10/21/18:29* @Description:*/
@Target( ElementType.TYPE) //注解定义到类上
@Retention( RetentionPolicy.RUNTIME) //生命周期
public @interface Sign {//    String value();
//    String message() ;SignCode value();}

import com.qycloud.iot.microserviceindoorpositioning.gps.config.GpsConfiguration;
import com.qycloud.iot.microserviceindoorpositioning.gps.domain.GpsProtocol;
import com.qycloud.iot.microserviceindoorpositioning.gps.handle.ISign;
import com.qycloud.iot.microserviceindoorpositioning.gps.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Autowired;import java.util.HashMap;
import java.util.Set;/*** @Author: WangHao* @Date: 2021/10/21/18:40* @Description:*/
@Slf4j
public class SignFactory {@AutowiredGpsConfiguration gpsConfiguration;private static HashMap<String,String> sourceMap = new HashMap<>();/*** 单例**/static {//反射工具包,指明扫描路径Reflections reflections = new Reflections("com.qycloud.iot.microserviceindoorpositioning");//获取带我们pay注解的类Set<Class<?>> classSet =  reflections.getTypesAnnotatedWith(Sign.class);//根据注解的值,将全类名放到map中for (Class clazz : classSet){Sign pay = (Sign) clazz.getAnnotation(Sign.class);sourceMap.put(pay.value().getCode(),clazz.getCanonicalName());}}public static ISign getInstance(GpsProtocol gpsProtocol){ISign chatType = null;try {//取得全类名String className = sourceMap.get(gpsProtocol.getSignCode());//取得类对象Class  clazz= Class.forName(className);//======================创建对象=====================chatType  =  (ISign) SpringUtils.getInterface(clazz);}catch (Exception e){log.error("尚未定义处理类标志:"+gpsProtocol.getSignCode()+"原始数据为:"+gpsProtocol.getRawData(),e);}return chatType;}}

/*** @Author: WangHao* @Date: 2021/10/22/13:51* @Description:*/
public enum SignCode {Sign_0002("0002", "终端心跳"),Sign_0100("0100", "终端注册"),Sign_0102("0102", "终端鉴权"),Sign_0104("0104", "查询终端参数应答"),Sign_0200("0200", "位置信息汇报"),Sign_0704("0704", "定位数据批量上传"),Sign_8001("8001", "平台通用应答"),Sign_8100("8100", "终端注册应答"),Sign_8104("8104", "查询终端参数"),;SignCode(String code, String desc) {this.code = code;this.desc = desc;}private String code;private String desc;public String getCode() {return code;}public String getDesc() {return desc;}}

开始解析


import com.qycloud.iot.microserviceindoorpositioning.gps.domain.GpsProtocol;
import com.qycloud.iot.microserviceindoorpositioning.gps.handle.ISign;
import com.qycloud.iot.microserviceindoorpositioning.gps.sign.SignFactory;
import com.qycloud.iot.microserviceindoorpositioning.gps.utils.GpsAnalyseUtils;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** @Author: WangHao* @Date: 2021/10/21/10:05* @Description: Gps协议数据解析类*/
@Component
@Slf4j
public class GpsProtocolDataHandler {/*** Gps** @param ctx* @param oriMsg*/public void handleProtocol(ChannelHandlerContext ctx, String oriMsg) {try {GpsProtocol gpsProtocol = GpsAnalyseUtils.handleGpsProtocol(oriMsg);if (null == gpsProtocol) return;ISign instance = SignFactory.getInstance(gpsProtocol);if (null != instance) {instance.handle(ctx, gpsProtocol);}} catch (Exception e) {log.error("原始数据:"+oriMsg);log.error("GPS错误信息:",e);e.printStackTrace();}}}
aa
aa
aa

基于netty实现gps jtt808协议接入相关推荐

  1. 基于Netty实现TCP私有协议

    什么是协议 从生活角度去理解:协议大部分情况下是指两个或两个以上实体为了开展某项活动,经过协商后双方达成的一致意见.例如租房合同协议.劳动合同协议等. 从互联网角度去理解:协议是指网络通信的参与方必须 ...

  2. 部标808协议 java_基于部标JT/T 808协议及数据格式的GPS服务器 开发

    部标808和809的出台,统一了产品的标准,统一了平台与终端之间的通讯协议,对于GPS运营商而言,只要平台支持部标,那可以选择任意一家的GPS车载终端,也不会受厂商的制约,GPS运营商在市场竞争过程中 ...

  3. 基于netty实现一个简单的支持http和webSocket协议的的服务器(含xxl-job通信模块源码分析)

    文章目录 背景 依赖 包结构 实现 WebSocketServer 业务handler WebSocketServerHandler 测试 xxl-job 源码中基于netty实现的http 总结 参 ...

  4. 基于netty的websocket协议实现

    基于netty的websocket协议实现 背景 1.启动服务端 2.测试服务端和客户端效果 背景 项目中使用到了websocket,所以查阅相关资料,完成了一个基于netty的websocket的实 ...

  5. netty 游戏服务器框图_基于Netty和WebSocket协议实现Web端自动打印订单服务方法与流程...

    本发明涉及电子商务技术领域,尤其涉及一种基于netty和websocket协议实现web端自动打印订单服务方法. 背景技术: 电子商务是以信息网络技术为手段,以商品交换为中心的商务活动:也可理解为在互 ...

  6. 基于Websocket草案10协议的升级及基于Netty的握手实现

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 最近发现 ...

  7. 基于netty搭建websocket,实现消息的主动推送

    基于netty搭建websocket,实现消息的主动推送 rpf_siwash https://www.jianshu.com/p/56216d1052d7 netty是由jboss提供的一款开源框架 ...

  8. 基于Netty的UDP服务端开发

    1.前言 之前基于Netty做了一套TCP与MQTT的服务端,随着系统接入的终端类型越来越多,出现了UDP通讯的设备,虽然这样的设备并非主流,而且通讯机制存在问题,为了考虑系统的兼容性,只能将整套服务 ...

  9. 移远BC20模组使用LwM2M协议接入华为IoT平台(NB-IoT专栏—进阶篇2)

    目录 1.背景 2.部署华为云 3.华为云与BC20模组进行数据收发实验 1.背景 最近在做一个智慧路灯项目,构思使用STM32结合NB-IoT模组实现数据上传和联动控制,并且可以使用GPS模块上传路 ...

  10. 基于 Netty 网络编程项目实战课程

    一 基于 Netty 网络编程项目实战课程 1项目介绍 2Netty 介绍与相关基础知识 2.1Netty 介绍 简介 Netty 是由 JBOSS 提供的一个 java 开源框架.Netty 提供异 ...

最新文章

  1. 女子质疑无限极产品致女儿心肌损害:将继续维权讨说法
  2. char* 长度_leetcode之最后一个单词的长度
  3. jdbc连接oracle_Oracle数据库性能监控|使用SiteScope 监控Oracle
  4. 利用DIV,实现简单的网页布局
  5. NYOJ 1272:表达式求值(2016河南省ACM-A)
  6. HDOJ--2544--最短路
  7. 中国智能手机行业的江湖事
  8. Tomcat7安装及配置教程
  9. quartus波形仿真破解MODELSIM
  10. 使用hexo+github搭建免费个人博客详细教程
  11. Google Earth Engine(GEE)——1981年至今全球逐日降水数据集(最终版)
  12. LSTM(长短期记忆网络)原理与在脑电数据上的应用
  13. git name consists only of disallowed characters:
  14. AmapUtil--高德地图工具类
  15. The Sultan's Successors UVA - 167
  16. 分贝通携手衡石科技,用心护好客户「钱袋子」 增收节流数百万
  17. Android出现没有资源包问题,Android打包出现的小问题汇总
  18. Appstore评分数据python实战
  19. 前端基础入门之css定位 position
  20. php ftp报错,ftp工具链接报错530错误详解

热门文章

  1. 万字总结:金融市场基础知识
  2. 图灵机器人官网 java_图灵机器人-Java/Android
  3. 161128、Redis 4.0发布及其新功能介绍
  4. SPOJ 4487 Splay 基本操作
  5. 两个9014三极管简易开关电路分析
  6. redis读中文 | fastjson 的 map、string、json 三者互转
  7. 使用mbw测试内存带宽性能
  8. 高等数学——多元函数极值的定义
  9. mysql select 列名_Mysql查询出所有列名
  10. 关于购买域名的一些建议