1.Netty的业务场景

​ 平台主要需求是和充电桩对接,并定时对设备进行监控检查,需要使用Netty作为通信中间件来监听端口,充电桩通过TCP连接向服务端发送指令,后台主要是通过netty的ChannelHandler来实现对硬件数据的接收和处理。

2. Netty的主要组件

2.1 Channel

​ Channel作为Netty网络通信的主体,可以看作是通讯的载体,主要有三个状态:打开、关闭、连接。

​ Channel主要的IO操作:读(read)、写(write)、连接(connect)、绑定(bind),均为异步,也就是说在调用如上方法后,并不保证IO操作完成,但会在IO操作成功、失败或取消后,生成相应的记录保存在一个凭证中并返回。

2.2 ChannelHandler

​ 负责Channel中的逻辑处理,可针对性地拦截处理Channel负责的IO操作或事件,然后在它的ChannelPipeline中将其递交给下一个handler。ChannelHandler中有许多方法需要实现,一般通过继承ChannelHandlerAdapter来实现。

2.3 ChannelPipeline

​ Netty中,ChannelPipeline相当于ChannelHandler的容器,它们可用于拦截和处理channel事件,关系如下图:

​ ChannelPipeline相当于ChannelHandler的容器,channel事件消息在ChannelPipeline中传播流动,而ChannelHandler可以针对性地对事件进行拦截处理、传递、忽略或者终止。一个ChannelHandler会绑定一个ChannelHandlerContext对象,ChannelHandler会通过与其对应的Context对象和ChannelPipeline交互,比如向上或向下传递events,动态地修改ChannelPipeline,或者通过ChannelHandlerContext中的AttributeKeys存储与handler相关的信息。

3. Netty服务端的启动

 ServerBootstrap serverBootstrap = new ServerBootstrap();    //启动NIO服务的辅助启动类serverBootstrap.group(parentGroup, childGroup).channel(NioServerSocketChannel.class)  //启动服务时, 通过反射创建一个NioServerSocketChannel对象//服务器初始化时执行, 属于AbstracBootstrap的方法.handler(new LoggingHandler(LogLevel.INFO))    //handler在初始化时就会执行,可以设置打印日志级别.option(ChannelOption.SO_BACKLOG, 1024)      //设置tcp缓冲区, 可连接队列大小.option(ChannelOption.SO_REUSEADDR, true)    //允许重复使用本地地址和端口//客户端连接成功之后执行, 属于ServerBootstrap的方法,继承自AbstractBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true)    //两小时没有数据通信时, 启用心跳保活机制探测客户端是否连接有效.childOption(ChannelOption.SO_REUSEADDR, true).childHandler(serverChannelInit);    //childHandler在客户端成功连接后才执行,实例化ChannelInitializerChannelFuture cf = serverBootstrap.bind(port).sync();    //绑定端口, 添加异步阻塞等待服务器启动完成if (cf.isSuccess() == true) {logger.info("NettyServer启动成功");} else {logger.error("NettyServer启动失败", cf.cause());}cf.channel().closeFuture().sync();    //等待服务器套接字关闭

4. Netty中的编解码

4.1 解码器

​ 解码(decode)就是根据约定的协议格式,对二进制数据进行解析解码(decode),这一功能由解码器(decoder)完成。这部分的主要工作是:确定协议、编写协议对应的解码器。Netty中有一套编解码框架,输入的数据由ChannelInboundHandler处理,自定义的解码器实际上就是这个接口的特殊实现类。

​ 对于解码器(decoder),Netty主要提供了抽象基类ByteToMessageDecoder和MessageToMessageDecoder。

4.1.1 抽象类ByteToMessageDecoder

​ 用于将接收的二进制数据(Byte)解码,得到完整有效的请求报文(Message)。

​ 一般ByteToMessageDecoder解码内容后,会得到一个ByteBuf实例,每个ByteBuf实例都包含了一个完整的报文信息。可以直接把这些ByteBuf实例交给之后的ChannelInboundHandler处理,或将ByteBuf实例解析封装到不同的Java实例对象后,再交给它处理。不管哪一种情况,之后的ChannelInboundHandler在处理时不需要再考虑粘包、拆包问题。

ByteToMessageDecoder中常见的实现类

  • FixedLengthFrameDecoder:定长协议解码器,可以指定固定字节数算一个完整报文

  • LineBasedFrameDecoder:行分隔符解码器,遇到\n或者\r\n,则认为是一个完整的报文

  • DelimiterBasedFrameDecoder:分隔符解码器,与LineBasedFrameDecoder类似,但可以自己指定分隔符

  • LengthFieldBasedFrameDecoder:长度编码解码器,将报文划分为报文头/报文体,根据报文头中的Length字段确定报文体的长度,因此报文体的长度是可变的

  • JsonObjectDecoder:json格式解码器,当检测到匹配数量的"{" 、”}”或”[””]”时,则认为是一个完整的json对象或json数组

    这些实现类,都只是将接收到的二进制数据解码,转成ByteBuf实例后直接交给之后的ChannelInboundHandler处理,并没有将ByteBuf实例中的信息封装到Java对象中,因为Netty并不清楚报文具体内容,以及需要封装到哪个Java对象,所以需要自己手动来解析ByteBuf实例并封装。

​ 可以自定义一个解码类继承ByteToMessageDecoder抽象类,重写它的decode方法:

protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;

参数列表:

  • ByteBuf in:解码前的二进制数据

  • List out:解码后的有效报文列表,由于tcp可能出现的粘包问题,入参的in中可能含有多个有效报文,所以需要将解码后的报文添加到List中,或者可能出现拆包,那么in中的数据就不足以构成一个有效报文,这时无需向List中添加元素。

​ 解码时需要尤其注意的是,应该先判断是否能构成一整个有效报文,再调用ByteBuf的read方法来读取数据,通过与in.readableBytes比较,来判断in中可读字节数是否大于约定的基本数据帧长度,只有在大于等于的情况下,我们才进行解码,即读取指定长度的字节,添加到List中。

4.1.2 抽象类MessageToMessageDecoder

​ 用于将一个本身就包含完整报文信息的对象转成另一个Java对象。

​ ByteToMessageDecoder解码后将包含了报文信息的ByteBuf实例交给后面的ChannelInboundHandler处理,此时可以在ChannelPipeline中再添加一个MessageToMessageDecoder,将ByteBuf中的信息解析后封装到Java对象中,简化接下来的ChannelInboundHandler操作。或者是要将已经封装好的Java对象转成其他Java对象,所以会出现MessageToMessageDecoder之后接着另一个MessageToMessageDecoder的情况。比如,Tomcat将浏览器发送过来的二进制数据解析为HttpServletRequest对象后,我们还需要将其中的数据提取出来封装成自定义的POJO类,即将现有的Java对象(HttpServletRequest)转换成另一个Java对象(POJO类)。

​ 继承MessageToMessageDecoder抽象类,也是要重写它的decode方法:

protected abstract void decode(ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception;

参数列表:

  • I msg:配置需要进行解码的参数

  • List out:经过MessageToMessageDecoder解析后,得到的Java对象存入列表

​ 那么在ChannelPipieline中它们的处理顺序如下:

ChannelPipieline ch=...
ch.addLast(new ByteToMessageDecoder());//ByteToMessageDecoder实现类
ch.addLast(new MessageToMessageDecoder());//MessageToMessageDecoder实现类
ch.addLast(new MessageToMessageDecoder());
...

​ 需要注意的是,即便是指定MessageToMessageDecoder的传入类型为ByteBuf,也绝对不可以用它来代替ByteToMessageDecoder报文解析的工作,因为ByteToMessageDecoder的内部设计才是针对接收到的二进制数据进行解码,所以除了解码,它其中还有对尚不完整的报文进行拆包缓存的功能逻辑,这是MessageToMessageDecoder所不具备的。

​ 因此,通常会先用ByteToMessageDecoder解析报文以及粘拆包处理,得到完整有效的ByteBuf实例,之后再交由一个或多个MessageToMessageDecoder对ByteBuf实例中的数据进行解析并封装成POJO类。

4.2 编码器

​ 相对应地,在ChannelOutboundHandler接口下,Netty也提供了MessageToByteEncoder和MessageToMessageEncoder两个抽象类来完成编码。没有解码器的内部逻辑复杂,编码只要将数据转成约定的二进制格式发送即可,而解码器除了解析数据,还要处理粘拆包问题。

4.3 编码解码器Codec

​ Codec同时具备编解码功能,它同时实现了ChannelInboundHandler和ChannelOutboundHandler两个接口,因此数据的输入输出都能处理。

​ Netty提供了一个ChannelDuplexHandler适配器类,编解码器的抽象基类ByteToMessageCodec和MessageToMessageCodec都继承了它,整体继承关系如下:

​ ByteToMessageCodec中维护了一个ByteToMessageDecoder和一个MessageToByteEncoder实例,结合二者的功能,泛型参数I可指定接受的编码类型:

public abstract class ByteToMessageCodec<I> extends ChannelDuplexHandler {private final TypeParameterMatcher outboundMsgMatcher;private final MessageToByteEncoder<I> encoder;private final ByteToMessageDecoder decoder = new ByteToMessageDecoder(){…}...protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception;protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;...
}

MessageToMessageCodec中维护了一个MessageToMessageDecoder和一个 MessageToMessageEncoder实例,结合二者的功能,泛型参数INBOUND_IN和OUTBOUND_IN分别表示需要解码和编码的数据类型:一个简单的总结:ByteToMessageCodec和MessageToMessageCodec中分别实现了字节和对象之间、对象和对象之间的编解码。

通过Netty实现与硬件设备(充电桩)通讯的功能相关推荐

  1. 充电桩管理系统php源码,充电桩通讯(调试工具源码)

    [实例简介] [实例截图] [核心代码] using System; using System.Collections.Generic; using System.ComponentModel; us ...

  2. ThinkPHP5中使用workman框架与硬件设备蓝牙锁通讯

    通篇分为三大块:服务器.蓝牙锁.APP 先说服务器: 使用的是TP5.workman框架使用composer安装的 安装wm可直接参考TP5的官方手册,讲解的很细致https://www.kanclo ...

  3. 使用STWI056WT-01串口屏充电桩项目

    新能源车历年增长,更好更便捷的充电桩需求旺盛,长城充电桩的规划是按目前需求设计的一个识别二维码移动支付的系统.该系统涉及移动APP.小程序扫描二维码,下载安装应用,注册用户名称.分配ID.登记车牌.手 ...

  4. 充电桩用linux系统吗,基于嵌入式Linux的电动汽车交流充电桩的设计

    基于嵌入式Linux 的电动汽车交流充电桩的设计 张 琳1,任鸿秋1,苏 新2 (1.太原理工大学电气与动力工程学院,山西太原030024:2.华北电力大学电气与电子工程学院,河北保定071003) ...

  5. OCPP1.6充电桩平台-海外版

    一.简介 OCPP1.6作为欧洲通用的充电协议,不管是平台还是充电桩硬件都需要支持本协议,这对于从事这一行业工作人员来说确实是一大福音,不需要每次针对不同的厂家都需要重来对接一次,作为一名软件工程师来 ...

  6. AcrelCloud-9500电瓶车充电桩应用场景分析

    AcrelCloud-9500电瓶车充电桩收费平台 在苏州市某街道的应用--安科瑞 崔远航 摘 要:全国各地电瓶车充电引发火灾的事故时有发生,对人民群众的生命财产安全造成了很大的威胁,本文介绍的苏州市 ...

  7. 电瓶车充电桩收费平台在福建学校的应用

    摘 要:全国各地电瓶车充电引发火灾的事故时有发生,对人民群众的生命财产安全造成了很大的威胁,本文介绍的电瓶车充电桩收费平台,采用无线通信技术.物联网技术和电气火灾探测及防护技术,对电瓶车充电桩的状态及 ...

  8. 电瓶车充电桩收费平台解决小区充电难的问题

    安科瑞 王冲   摘 要:全国各地电瓶车充电引发火灾的事故时有发生,对人民群众的生命财产安全造成了很大的威胁,本文介绍的苏州市某拆迁小区,是海虞镇为创建市级消防安全"331"示范社 ...

  9. AcrelCloud-9500电瓶车充电桩收费平台在公共场所中的应用

    1 项目概述 福建大学城某学院是福建省人民政府举办的省属公学院,学校占地面积1388亩,设有13个二级学院和2个教学部,现有专任教师总数771人,全日制本科在校生近1.5万人. 学院为了满足校园与日俱 ...

最新文章

  1. android蓝牙python,Android蓝牙连接问题
  2. 基于计算机网络的可持续发展信息共享情况调查
  3. mysql中0和空值_SQL中空值 和NULL的概念:
  4. matlab层次分析法代码_基于主成分分析法和层次分析法的工程项目经理胜任力评价研究...
  5. 瑞斯凯X9D Plus无法连接DCL模拟器的解决方法
  6. Jquery colorbox不错的遮罩
  7. day69_淘淘商城项目_02_dubbo介绍 + dubbo框架整合 + zookeeper + 商品列表查询实现 + 分页 + 逆向工程_匠心笔记
  8. php html转ubb,PHP HTML转UBB函数
  9. OSPF协议邻居(Neighbor)与邻接(Adjacency)关系
  10. 不看你就亏了。。。。
  11. Java版漏斗计时器_新学期新气象 教你在《我的世界》做出特别铃声
  12. Frontiers in Neuroscience:弥散张量成像(DTI)研究指南
  13. 基于51单片机的12864液晶演示器驱动
  14. windows7下cmd命令窗口没有滚动条的解救方法
  15. 插件!crx插件包下载网址与安装方法!!
  16. 淘宝足迹新玩法,如何通过足迹增加商品曝光量,打标后足迹不出解决方法,淘宝详情页的下拉出现足迹怎么实现的
  17. 苏州源特VPT87DDF01B 隔离变压器 小体积/SMD/3000VDC 隔离
  18. JMeter-01-性能测试基础知识介绍
  19. MySQL运行原理与基础架构
  20. SAP报工时修改工作中心

热门文章

  1. 你好,我的Dev-C++ 5.15被烦人的360杀毒软件给删了,放到白名单里之后就360竟然把所有的浏览器全部删掉了,请问怎么办
  2. linux固态硬盘寿命,选SSD固态硬盘不必太纠结TLC MLC的寿命问题
  3. 四通OKI 5330SC 针式打印机驱动
  4. 【安信可NB-IoT模组EC系列应用笔记⑥】AT指令HTTP请求一篇就够
  5. matlab绘制子图怎么,MATLAB画图之多子图画法(subplot和自己确定大小位置两种方法)...
  6. acwing-献给阿尔吉侬的花束
  7. Github每日精选(第68期):HTTP客户端哪家强-reqwest
  8. 在一个路由器上连接另外一个路由器
  9. Go为什么天生支持高并发
  10. 在线视频解析下载教程合集(值得收藏)