搭建框架的目标
相信写过IOT服务的伙伴应该知道,面对各种千奇百怪的通信协议,特别是16进制报文的协议,有些协议看的确实有点让人头疼。但这些协议中也有很多共性,不必针对每过协议都把一些业务无关的代码再撸一遍。
搭建这个项目主要是针对常见的TCP连接为基础的设备通信协议做一些抽象及规范化处理,减低一些开发的成本,目标是实现一个可配置的,便于扩展各种协议的框架。
Vertx简介
Vert.x是Eclipse基金会下面的一个开源项目,Vert.x的基本定位是一个事件驱动的编程框架,通过Vert.x使用者可以用相对低的成本就享受到NIO带来的高性能。netty是Vert.x底层使用的通讯组件,Vert.x为了最大限度的降低使用门槛,刻意屏蔽掉了许多底层netty相关的细节,比如ByteBuf、引用计数等等。
本文主要见解的是搭建一个可配置和可扩展的IOT服务,并不会详细展开讲解Vertx,Vertx相关内容可上官网查看《vertx官网》
IOT通信中的常见概念
1.logicAddress
逻辑通信地址。在常见的设备协议中,都会有逻辑通信地址这个概念,用于标识当前的连接是具体的某个设备。有了这个逻辑地址之后就可以很方便的找到这个连接。
在业务系统中建立档案的时候用这个地址,后续也可以通过这个通信地址将指定的命令下发给指定的设备。
2.messageType
消息类型。在TCP通信中,设备上报的不止一类消息,但在常见的设备通信协议中都会针对不同的消息做不同的标识,借此来区分每条上传消息的含义。所以在设备上报的报文中我们根据通信协议的定义找到报文的标识位,然后再做对应的处理。
3.session
会话。session主要用于管理连接。设备和服务端建立连接之后会产生一个socket,但很多时候这个socket缺少一些语义和描述,所以我们会对这个socket做一些包装,比如抽象一些方法,绑定设备的逻辑地址以便后续查找和调用。
代码架构流程
整体的核心流程如下:

核心代码分析
yaml文件配置
配置多个协议的协议名称和协议通信端口号,这里用多个端口区分不同的协议,避免协议内容相近的时候出现解析错误的情况。
protocols:
- name: ZHONGXING #中兴
port: 8898
- name: HUAWEI #华为
port: 9666
ProtocolServerBootstrap
这里主要是加载yaml配置,然后启动相应的TcpServer服务监听端口,并根据配置定义找打对应协议的编解码器,将消息转发到对应的编解码器中。
这里用到了两个自定义注解:
@CodecScan:标识编解码器要扫描哪些包。
@Protocol:注解来标识编解码器对应的通信协议。
/**
* @author yan
* @date 2023/9/12
*/
@Slf4j
public class ProtocolServerBootstrap extends AbstractVerticle {
private Class starter;
private static Map protocols = new ConcurrentHashMap<>();
private static Map codecMap = new ConcurrentHashMap<>();
public ProtocolServerBootstrap(Class starter) {
this.starter = starter;
}
@Override
public void init(Vertx vertx, Context context) {
super.init(vertx, context);
loadProfile();
loadProtocolCodec();
}
public void loadProfile() {
InputStream inputStream = null;
try {
inputStream = this.getClass().getClassLoader().getResourceAsStream("protocol.yml");
Yaml yaml = new Yaml();
Map> map = yaml.load(inputStream);
List