🏗️ 架构概览
Snet 遵循严格的三层架构:模型层 -> 核心层 -> 插件层。每一层都有明确定义的职责和依赖方向。
层次结构图
+---------------------------------------------------------------+
| 插件层 (PLUGINS) |
| ModbusOperate SiemensOperate MitsubishiOperate MqttClient |
| ModbusData SiemensData MitsubishiData MqttData |
+---------------------------------------------------------------+
| 核心层 (CORE) |
| DaqAbstract<O,D> MqAbstract<O,D> |
| CommunicationAbstract<O,D> |
| |
| CoreUnify<O,D> | Channel | Cache | WebAPI | Events |
| Bytes Transform | Reflection | Virtual Address |
+---------------------------------------------------------------+
| 模型层 (MODEL) |
| IDaq | IMq | ICommunication | 14+ 子接口 |
| OperateResult | Address | EventDataResult | LanguageType |
+---------------------------------------------------------------+
类继承层次
每个操作类都追溯到 CoreUnify<O, D>:
CoreUnify<O, D>
(ICreateInstance, ILanguage, 单例管理, 事件, 日志)
|
+-- DaqAbstract<O, D>
| (IDaq, 8个抽象异步方法, 6个WebAPI端点)
| |
| +-- ModbusOperate : DaqAbstract<ModbusOperate, ModbusData.Basics>
| +-- SiemensOperate : DaqAbstract<SiemensOperate, SiemensData.Basics>
| +-- MitsubishiOperate, OmronOperate, 等.
|
+-- MqAbstract<O, D>
| (IMq, 异步发布/订阅管道)
| |
| +-- MqttClientOperate : MqAbstract<MqttClientOperate, MqttClientData.Basics>
| +-- KafkaOperate, RabbitMQOperate, 等.
|
+-- CommunicationAbstract<O, D>
(ICommunication)
|
+-- TcpClientOperate, TcpServiceOperate, UdpOperate,
SerialOperate, WsClientOperate, WsServiceOperate,
HttpClientOperate, HttpServiceOperate
关键设计:MQTT 不继承 DaqAbstract
MqttClientOperate 继承自 MqAbstract,而不是 DaqAbstract。这意味着 MQTT:
- 使用
IProducer/IConsumer而不是IRead/IWrite - 没有 WebAPI 端点
- 不以
SubscribeData.SCData作为数据类的基类 - 没有
WAOn/WAOff
CoreUnify<O, D> -- 基础层
CoreUnify<O, D> 提供每个 Snet 类共享的能力:
| 特性 | 实现方式 |
|---|---|
| 单例池 | ConcurrentDictionary<D, O> 配合 SemaphoreSlim 锁定,最大255个实例 |
| 时间追踪 | BegOperateAsync() / EndOperateAsync() 自动记录 RunTime(毫秒) |
| 事件 | OnDataEvent/Async, OnInfoEvent/Async, OnLanguageEvent/Async |
| 日志 | 基于 Serilog,使用 LogOperateSet / LogOperateGet |
| 多语言 | GetLanguageAsync() / SetLanguageAsync() 带事件传播 |
| 参数反射 | GetParamAsync() 返回带子集信息的类型化 ParamModel |
DaqAbstract<O, D> -- 数据采集管道
继承自 CoreUnify 并实现 IDaq。所有协议特定的操作类都继承此类。
8个抽象方法
每个 DAQ 协议必须实现:
public abstract Task<OperateResult> OnAsync(CancellationToken token);
public abstract Task<OperateResult> OffAsync(bool isForce, CancellationToken token);
public abstract Task<OperateResult> ReadAsync(Address address, CancellationToken token);
public abstract Task<OperateResult> WriteAsync(ConcurrentDictionary<string, WriteModel> data, CancellationToken token);
public abstract Task<OperateResult> SubscribeAsync(Address address, CancellationToken token);
public abstract Task<OperateResult> UnSubscribeAsync(Address address, CancellationToken token);
public abstract Task<OperateResult> GetStatusAsync(CancellationToken token);
public abstract Task<OperateResult> GetBaseObjectAsync(CancellationToken token);
3个必需属性
protected virtual string CN { get; } // 中文名称
protected virtual string CD { get; } // 中文描述
protected virtual List<propertie> AP { get; } // 附加属性
6个内置 WebAPI 端点
每个 DAQ 设备自动暴露以下端点:
| 端点 | 方法 | 用途 |
|---|---|---|
/api/on |
POST | 打开连接 |
/api/off |
POST | 关闭连接 |
/api/read |
POST | 读取数据(请求体:Address JSON) |
/api/write |
POST | 写入数据(请求体:WriteModel 字典 JSON) |
/api/getstatus |
POST | 获取设备状态 |
/api/switchlanguage |
POST | 切换中/英文语言 |
MqAbstract<O, D> -- 消息管道
继承自 CoreUnify 并实现 IMq。用于 MQTT、Kafka、RabbitMQ、NetMQ 和 Netty。
提供 IProducer(发布)和 IConsumer(订阅),而不是 IRead/IWrite。使用 AddressMq(基于主题)而不是 Address(基于寄存器)。
CommunicationAbstract<O, D> -- 传输层
8个通信类的基类:TcpClientOperate、TcpServiceOperate、UdpOperate、SerialOperate、WsClientOperate、WsServiceOperate、HttpClientOperate、HttpServiceOperate。
详见通信层。
内置核心工具
| 工具 | 描述 | 关键类型 |
|---|---|---|
| Channel(通道) | System.Threading.Channels 封装器 |
ChannelOperate<T> |
| Caching(缓存) | MemoryCache + MemoryMappedFile |
ProcessCacheOperate, ShareCacheOperate |
| Bytes Transform(字节转换) | 字节序 + 编码转换 | DataFormat, BytesHandler |
| Virtual Address(虚拟地址) | 模拟/测试地址 | 5种虚拟地址类型 |
| Reflection(反射) | DLL 扫描和动态调用 | ReflectionOperate |
| Events(事件) | EventingWrapperAsync 模式 | EventingWrapperAsync<T> |
