Snet 框架核心架构
源码路径: Snet.Core/
命名空间根: Snet.Core
概述
Snet 框架是一个统一的工业数据平台,构建于单一基类 CoreUnify<O, D> 之上。所有操作组件(PLC 驱动、通信客户端、消息队列、缓存、插件、虚拟地址处理器)都继承自此根基类。该框架提供了一致的单例生命周期、结构化事件系统、内置计时/日志记录、多语言支持以及跨所有子系统的标准化 OperateResult 契约。
架构图
+-------------------------------+
| CoreUnify<O, D> |
| (extend/CoreUnify.cs) |
| |
| 单例池 (最大 255 实例) |
| 3 对事件 (同步+异步) |
| 计时 (Beg/EndOperate) |
| Serilog 日志 |
| 多语言 (zh/en) |
| 反射参数 |
+-------------+-----------------+
|
+-----------------+----------+--------+----------+----------------+
| | | | |
DaqAbstract CommunicationAbstract MqAbstract CommunicationService Direct
(IDaq) (ICommunication) (IMq) Abstract Subclasses
| | | (ICommunicationService) |
+-----+-----+ +------+------+ +-----+-----+ +----+----+ +---+---+
| 33 种驱动 | | SerialOperate| | MqttClient | |TcpService| |Subscribe|
| Snet.DB | | TcpClient | | Kafka | |WsService | |Channel |
| Snet.Sim | | WsClient | | RabbitMQ | |UdpService| |MqOperate|
| Snet.TEP | | UdpClient | | NetMQ | |HttpClient|
| Snet.Opc | | UdpMulticast | | NettyClient| |HttpService|
| UdpBroadcast | |Reflection |
+--------------+ |VirtualAddr|
|BytesHandler|
|ShareCache |
|ProcessCache|
|Plugin |
+-----------+
1. CoreUnify <O, D> -- 万法之基
文件: Snet.Core/extend/CoreUnify.cs
命名空间: Snet.Core.extend
实现接口: IGetParam, ICreateInstance, IEvent, ILog, ILanguage, IDisposable, IAsyncDisposable
类型约束: where O : class, where D : class
CoreUnify 是框架中所有操作组件的根基类。O 是操作者类型(正在定义的具体类),D 是配置/基础数据类型,用作单例字典的键。
1.1 单例池
protected static readonly ConcurrentDictionary<D, O> objList = new ConcurrentDictionary<D, O>();
protected static readonly int maxInstanceCount = byte.MaxValue; // 255
每个派生类共享一个静态字典,将配置对象(D)映射到其单例操作者实例(O)。池的上限为 255 个实例。实例创建由 SemaphoreSlim(1, 1) 保护,防止竞争条件。
1.2 实例工厂
// 异步 -- 推荐使用
public static async Task<O> InstanceAsync(D? param = null, CancellationToken token = default)
// 同步便捷包装
public static O Instance(D? param = null)
工厂算法:
- 如果
param为 null,通过Activator.CreateInstance创建默认D。 - 获取信号量。
- 在
objList中精确匹配键。 - 如果未找到,通过对所有现有键执行
Comparer(param).result进行深度比较查找。 - 如果仍未找到匹配,调用私有方法
CreateInstance(param),使用反射调用构造函数typeof(O).GetConstructor([typeof(D)])。 - 通过
TryAdd将新实例添加到objList。
使用示例:
// 创建或获取 Modbus RTU 驱动实例
var basics = new ModbusData
{
IP = "192.168.1.100",
Port = 502,
StationNo = 1
};
var modbus = await ModbusOperate.InstanceAsync(basics);
// 后续使用等效数据的调用返回的是同一个实例
var sameModbus = await ModbusOperate.InstanceAsync(basics);
// modbus == sameModbus (同一个对象引用)
// 打开连接、读取数据、关闭连接
await modbus.OnAsync();
var result = await modbus.ReadAsync(new Address
{
SN = Guid.NewGuid().ToString(),
AddressArray = new List<AddressDetails>
{
new AddressDetails { AddressName = "D100", AddressDataType = DataType.Int }
}
});
await modbus.OffAsync();
1.3 计时 -- BegOperate / EndOperate
每个方法都可以用计时调用来封装其执行过程,生成标准化的 OperateResult:
// 方法开始 -- 记录开始时间戳
string methodName = await BegOperateAsync(token);
// 方法结束 -- 计算耗时(毫秒),格式化本地化日志消息
return await EndOperateAsync(
status: true,
message: "操作完成",
resultData: someResult,
token: token
);
EndOperate 会自动:
- 通过
TimeHandler.StopRecord()计算耗时(毫秒)。 - 格式化包含组件标签、方法名、成功/失败状态、源文件和行号的日志消息。
- 如果
status == false且logOutput == true,通过LogHelper.ErrorAsync(Serilog)写入错误条目。 - 返回
OperateResult(status, message, runTime, resultData)。
1.4 事件 -- 三对同步/异步事件
| 同步事件 | 异步事件包装器 | 事件参数类型 |
|---|---|---|
OnDataEvent |
OnDataEventAsync(通过 EventingWrapperAsync) |
EventDataResult |
OnInfoEvent |
OnInfoEventAsync(通过 EventingWrapperAsync) |
EventInfoResult |
OnLanguageEvent |
OnLanguageEventAsync(通过 EventingWrapperAsync) |
EventLanguageResult |
每个异步事件使用私有的 EventingWrapperAsync<T> 实例,提供 AddHandler/RemoveHandler 方法。受保护的 OnDataEventHandler / OnInfoEventHandler / OnLanguageEventHandler 方法同时触发同步和异步订阅者。语言事件在构造函数中自动注册,在 Dispose/DisposeAsync 中注销,使用缓存的委托实例以防止内存泄漏。
订阅事件:
var modbus = await ModbusOperate.InstanceAsync(basics);
// 同步处理程序
modbus.OnDataEvent += (sender, e) =>
{
Console.WriteLine($"收到数据: {e.GetSource<SomeDataType>()}");
};
// 异步处理程序(安全即发即忘)
modbus.OnDataEventAsync += async (sender, e) =>
{
var data = e.GetSource<SomeDataType>();
await SaveToDatabaseAsync(data);
};
1.5 日志 -- Serilog 集成
LogOperateSet / LogOperateGet 控制底层 LogHelper 使用的 LogModel 配置:
// 配置日志及通知回调
await modbus.LogOperateSetAsync(
logOut: true,
consoleOut: true,
notice: (source, level, message, ex) =>
{
// 自定义通知逻辑
}
);
同时支持同步 Action<...> 和异步 Func<..., Task> 通知回调。
1.6 多语言 -- ILanguage
// 获取翻译值
string translated = modbus.GetLanguageValue("openSuccess");
// 运行时切换语言
modbus.SetLanguage(LanguageType.en); // 英文
modbus.SetLanguage(LanguageType.zh); // 中文
// 异步变体
string translated = await modbus.GetLanguageValueAsync("openSuccess", token: token);
语言值通过 LanguageHandler 静态委托系统解析。切换语言会在所有已注册实例上触发 OnLanguageEvent/OnLanguageEventAsync。
1.7 参数自省 -- IGetParam
GetParam() 使用反射生成适用于动态 UI 表单生成的参数树:
var result = await modbus.GetParamAsync();
// result.ResultData 包含一个 ParamModel,其中有所有可配置属性
// 原始基础数据
var rawResult = await modbus.GetParamAsync(getBasicsParam: true);
// 自动分配参数(遵循 AutoAllocatingTagAttribute 特性)
var autoParam = await modbus.GetAutoAllocatingParamAsync();
1.8 构造函数链
// 无参:调用 RegisterLanguageEvent()
protected CoreUnify()
// 有参:存储 basics,然后 RegisterLanguageEvent()
protected CoreUnify(D param)
1.9 资源清理
// Dispose 从单例字典中移除并注销语言事件
public virtual void Dispose()
{
UnregisterLanguageEvent();
objList?.Remove(basics, out _);
GC.SuppressFinalize(this);
}
2. DaqAbstract <O, D> -- 数据采集基类
文件: Snet.Core/abstract/DaqAbstract.cs
继承: CoreUnify<O, D>
实现: IDaq
所有数据采集驱动程序(PLC、OPC、数据库、仿真)的基类。它扩展了 CoreUnify,增加了 WebApi 远程控制能力和类型安全的写入重载。静态构造函数注册 CodePagesEncodingProvider 以支持 GB2312 编码。
2.1 抽象方法(具体驱动程序必须实现)
| 方法 | 签名 | 用途 |
|---|---|---|
OnAsync |
Task<OperateResult> OnAsync(CancellationToken) |
激活/打开设备连接 |
OffAsync |
Task<OperateResult> OffAsync(bool hardClose, CancellationToken) |
停用/关闭,支持可选的硬关闭 |
ReadAsync |
Task<OperateResult> ReadAsync(Address, CancellationToken) |
从指定地址读取数值 |
WriteAsync |
Task<OperateResult> WriteAsync(ConcurrentDictionary<string, (object, EncodingType?)>, CancellationToken) |
将类型化数值写入地址 |
SubscribeAsync |
Task<OperateResult> SubscribeAsync(Address, CancellationToken) |
启动周期性轮询订阅 |
UnSubscribeAsync |
Task<OperateResult> UnSubscribeAsync(Address, CancellationToken) |
停止订阅 |
GetBaseObjectAsync |
Task<OperateResult> GetBaseObjectAsync(CancellationToken) |
返回底层通信对象 |
GetStatusAsync |
Task<OperateResult> GetStatusAsync(CancellationToken) |
返回当前设备状态 |
2.2 WebApi 集成
DaqAbstract 通过 WAOn/WAOff/WAStatus 提供内置的 HTTP API 端点用于远程设备控制:
| 端点 | HTTP | 用途 | 参数 |
|---|---|---|---|
/api/on |
POST | 打开设备连接 | 无 |
/api/off |
POST | 关闭设备连接 | 无 |
/api/read |
POST | 从地址读取 | 请求体中传入 Address 对象 |
/api/write |
POST | 写入地址 | 请求体中传入 ConcurrentDictionary<string, WriteModel> |
/api/getstatus |
POST | 获取设备状态 | 无 |
/api/switchlanguage |
POST | 切换中英文 | 无 |
// 为驱动程序激活 WebApi
var wam = new WAModel { IpAddress = "0.0.0.0", Port = 8080 };
await modbus.WAOnAsync(wam);
// 现在可通过 HTTP 访问:POST http://localhost:8080/api/read
// 请求体:{ "SN": "...", "AddressArray": [{"AddressName":"D100","AddressDataType":"Int"}] }
2.3 写入重载
三种写入重载用于不同的数据表示:
// 原始 (value, encoding) 元组
await driver.WriteAsync(new ConcurrentDictionary<string, (object, EncodingType?)>
{
["D100"] = (123, null),
["D101"] = (45.6f, null)
});
// 普通对象值(默认为 ASCII 编码)
await driver.WriteAsync(new ConcurrentDictionary<string, object>
{
["D100"] = 123,
["D101"] = 45.6f
});
// 带有显式 DataType 的 WriteModel(自动转换)
await driver.WriteAsync(new ConcurrentDictionary<string, WriteModel>
{
["D100"] = new WriteModel { Value = 99.1, AddressDataType = DataType.Float }
});
2.4 具体驱动程序
以下全部继承自 DaqAbstract<O, D>:
PLC 驱动(32+ 种): Snet.Siemens(西门子)、Snet.Mitsubishi(三菱)、Snet.Omron(欧姆龙)、Snet.AllenBradley(AB)、Snet.Beckhoff(倍福)、Snet.Cimon、Snet.Delta(台达)、Snet.Fanuc(发那科)、Snet.Fatek(永宏)、Snet.Freedom、Snet.Fuji(富士)、Snet.GE(通用电气)、Snet.Inovance(汇川)、Snet.Invt(英威腾)、Snet.Keyence(基恩士)、Snet.Kossi(顾美)、Snet.LSis、Snet.MegMeet(麦格米特)、Snet.Modbus、Snet.OrientalMotor(东方马达)、Snet.Panasonic(松下)、Snet.RKC、Snet.Toyota(丰田)、Snet.Turck(图尔克)、Snet.Vigor(丰炜)、Snet.WeCon(维控)、Snet.XinJE(信捷)、Snet.Yamatake(山武)、Snet.Yaskawa(安川)、Snet.Yokogawa(横河)、Snet.YuDian(宇电)
其他 DAQ: Snet.DB(数据库驱动)、Snet.Sim(仿真设备)、Snet.TEP(TepMaster)、Snet.Opc(OpcDaClient、OpcDaHttp、OpcUaClient)
3. MqAbstract <O, D> -- 消息队列基类
文件: Snet.Core/abstract/MqAbstract.cs
继承: CoreUnify<O, D>
实现: IMq
消息队列/消息代理集成的基类。在异构 MQ 实现之上提供一致的生产/消费抽象。
3.1 抽象方法
| 方法 | 签名 | 用途 |
|---|---|---|
OnAsync |
Task<OperateResult> OnAsync(CancellationToken) |
打开与代理的连接 |
OffAsync |
Task<OperateResult> OffAsync(bool, CancellationToken) |
关闭连接 |
ProduceAsync |
Task<OperateResult> ProduceAsync(string topic, byte[], CancellationToken) |
将二进制负载发布到主题 |
ConsumeAsync |
Task<OperateResult> ConsumeAsync(string topic, CancellationToken) |
开始从主题消费 |
UnConsumeAsync |
Task<OperateResult> UnConsumeAsync(string topic, CancellationToken) |
停止从主题消费 |
GetStatusAsync |
Task<OperateResult> GetStatusAsync(CancellationToken) |
返回代理连接状态 |
3.2 字符串转字节的便捷方法
// 具体实现:使用默认 UTF-8 或指定编码将字符串序列化为 byte[]
public virtual Task<OperateResult> ProduceAsync(
string topic, string content, Encoding? encoding = null, CancellationToken token = default)
{
return ProduceAsync(topic,
encoding == null ? Encoding.UTF8.GetBytes(content) : encoding.GetBytes(content));
}
3.3 具体 MQ 实现
| 包 | 类 | 协议 |
|---|---|---|
Snet.Mqtt |
MqttClientOperate |
MQTT 3.1.1 / 5.0 |
Snet.Kafka |
Kafka client | Apache Kafka |
Snet.RabbitMQ |
RabbitMQ client | AMQP 0-9-1 |
Snet.NetMQ |
NetMQ client | ZeroMQ(C# 原生) |
Snet.Netty |
Netty client | 基于 TCP 的自定义 MQ |
3.4 使用示例
var mqttData = new MqttClientData
{
IP = "broker.emqx.io",
Port = 1883,
ClientId = "snet-client-001"
};
var mqtt = await MqttClientOperate.InstanceAsync(mqttData);
await mqtt.OnAsync();
await mqtt.ProduceAsync("snet/data", "{\"temp\": 23.5}");
await mqtt.ConsumeAsync("snet/commands");
await mqtt.OffAsync();
4. CommunicationAbstract <O, D> -- 客户端通信基类
文件: Snet.Core/abstract/CommunicationAbstract.cs
继承: CoreUnify<O, D>
实现: ICommunication
客户端通信传输(出站连接)的基类。
4.1 抽象方法
| 方法 | 用途 |
|---|---|
OnAsync |
连接到远程端点 |
OffAsync(bool hardClose) |
断开连接 |
SendAsync(byte[]) |
发送原始字节 |
SendWaitAsync(byte[], CancellationToken) |
发送并等待响应 |
GetBaseObjectAsync |
返回底层 socket/客户端对象 |
GetStatusAsync |
返回连接状态 |
4.2 具体实现
| 类 | 文件 | 传输方式 |
|---|---|---|
SerialOperate |
communication/serial/SerialOperate.cs |
RS-232/RS-485 |
TcpClientOperate |
communication/net/tcp/client/TcpClientOperate.cs |
TCP/IP |
WsClientOperate |
communication/net/ws/client/WsClientOperate.cs |
WebSocket |
UdpClientOperate |
communication/net/udp/unicast/client/UdpClientOperate.cs |
UDP 单播 |
UdpMulticastOperate |
communication/net/udp/multicast/UdpMulticastOperate.cs |
UDP 组播 |
UdpBroadcastOperate |
communication/net/udp/broadcast/UdpBroadcastOperate.cs |
UDP 广播 |
4.3 资源清理
public override void Dispose()
{
Off(true); // 先硬关闭连接
base.Dispose(); // 从单例池中移除,注销事件
}
5. CommunicationServiceAbstract <O, D> -- 服务端通信基类
文件: Snet.Core/abstract/CommunicationServiceAbstract.cs
继承: CoreUnify<O, D>
实现: ICommunicationService
服务端通信传输(入站监听)的基类。
5.1 抽象方法
| 方法 | 用途 |
|---|---|
OnAsync |
启动服务端监听 |
OffAsync(bool hardClose) |
停止服务端 |
SendAsync(byte[], string[]?) |
向多个目标客户端发送字节 |
SendAsync(byte[], string) |
向指定客户端发送字节 |
RemoveAsync(string[]) |
移除/断开指定客户端连接 |
GetBaseObjectAsync |
返回底层服务端对象 |
GetStatusAsync |
返回服务端状态及已连接客户端 |
5.2 具体实现
| 类 | 文件 |
|---|---|
TcpServiceOperate |
communication/net/tcp/service/TcpServiceOperate.cs |
WsServiceOperate |
communication/net/ws/service/WsServiceOperate.cs |
UdpServiceOperate |
communication/net/udp/unicast/service/UdpServiceOperate.cs |
6. 完整继承层次结构
CoreUnify<O, D> (Snet.Core/extend/CoreUnify.cs)
|
+-- DaqAbstract<O, D> (Snet.Core/abstract/DaqAbstract.cs) [IDaq]
| +-- 所有 PLC 驱动(32+ 个包:Siemens、Mitsubishi、Omron、AB 等)
| +-- Snet.DB(数据库)
| +-- Snet.Sim(仿真)
| +-- Snet.TEP(TepMaster)
| +-- Snet.Opc(OpcDaClient、OpcDaHttp、OpcUaClient)
|
+-- CommunicationAbstract<O, D> (Snet.Core/abstract/CommunicationAbstract.cs) [ICommunication]
| +-- SerialOperate(串口操作)
| +-- TcpClientOperate(TCP 客户端操作)
| +-- WsClientOperate(WebSocket 客户端操作)
| +-- UdpClientOperate(UDP 单播客户端操作)
| +-- UdpMulticastOperate(UDP 组播操作)
| +-- UdpBroadcastOperate(UDP 广播操作)
|
+-- CommunicationServiceAbstract<O,D> (Snet.Core/abstract/CommunicationServiceAbstract.cs) [ICommunicationService]
| +-- TcpServiceOperate(TCP 服务端操作)
| +-- WsServiceOperate(WebSocket 服务端操作)
| +-- UdpServiceOperate(UDP 单播服务端操作)
|
+-- MqAbstract<O, D> (Snet.Core/abstract/MqAbstract.cs) [IMq]
| +-- Snet.Mqtt (MqttClientOperate)
| +-- Snet.Kafka
| +-- Snet.RabbitMQ
| +-- Snet.NetMQ
| +-- Snet.Netty (NettyClient)
|
+-- SubscribeOperate (Snet.Core/subscribe/SubscribeOperate.cs)
+-- SubscribeSource<T> (Snet.Core/subscribe/core/SubscribeSource.cs)
+-- SubscribeService<T> (Snet.Core/subscribe/core/SubscribeService.cs)
+-- HttpServiceOperate (Snet.Core/communication/net/http/service/HttpServiceOperate.cs)
+-- HttpClientOperate (Snet.Core/communication/net/http/client/HttpClientOperate.cs)
+-- ChannelOperate<T> (Snet.Core/channel/ChannelOperate.cs)
+-- MqOperate (Snet.Core/mq/MqOperate.cs)
+-- ReflectionOperate (Snet.Core/reflection/ReflectionOperate.cs)
+-- VirtualAddress (Snet.Core/virtualAddress/VirtualAddress.cs)
+-- BytesHandler (Snet.Core/handler/BytesHandler.cs)
+-- ShareCacheOperate (Snet.Core/cache/share/ShareCacheOperate.cs)
+-- ProcessCacheOperate (Snet.Core/cache/process/ProcessCacheOperate.cs)
+-- PluginOperate (Snet.Core/plugin/PluginOperate.cs)
7. 核心设计模式
7.1 配置即键的单例池
每个 CoreUnify 子类拥有一个 static ConcurrentDictionary<D, O>。配置对象 D 同时充当构造参数和字典键。深度比较确保等效配置返回相同实例。255 实例上限防止无限制的资源消耗。
7.2 OperateResult -- 统一返回信封
每个方法都返回 OperateResult,它包含:
Status(bool)-- 成功/失败指示器Message(string)-- 人类可读的本地化描述RunTime(int)-- 执行时间(毫秒)ResultData(object?)-- 实际负载
// 成功
return OperateResult.CreateSuccessResult("读取完成", rawData);
// 失败
return OperateResult.CreateFailureResult("连接超时");
7.3 抽象方法 + 具体便捷实现
抽象基类定义了子类必须实现的异步契约。同步重载作为便捷包装,使用 GetAwaiter().GetResult()。此模式防止调用者在异步上下文中意外阻塞,同时仍为控制台应用和脚本提供简单的同步 API。
7.4 WebApi 远程控制
DaqAbstract 内嵌了一个 HTTP 服务器(HttpServiceOperate),将设备操作暴露为 REST 端点。这使得任何 DAQ 驱动程序都可以在无需额外基础设施的情况下进行远程控制。
8. 包依赖
| 包 / 命名空间 | 角色 |
|---|---|
Snet.Core |
框架核心:所有抽象类、扩展类、通信、缓存、通道、MQ、插件、反射、订阅、虚拟地址 |
Snet.Model |
数据模型、接口(IDaq、IMq、ICommunication 等)、枚举、事件参数类型 |
Snet.Log |
封装 Serilog 的日志抽象层 |
Snet.Utility |
工具类(JSON、字节、反射、时间、比较) |
Snet.{Vendor} |
各厂商 PLC 驱动包(每个都继承 DaqAbstract) |
Snet.Mqtt |
MQTT 客户端(继承 MqAbstract) |
Snet.Kafka |
Kafka 客户端(继承 MqAbstract) |
Snet.RabbitMQ |
RabbitMQ 客户端(继承 MqAbstract) |
Snet.NetMQ |
NetMQ/ZeroMQ 客户端(继承 MqAbstract) |
Snet.Netty |
Netty 客户端(继承 MqAbstract) |
Snet.Opc |
OPC DA / OPC UA 客户端(继承 DaqAbstract) |
Snet.DB |
数据库 DAQ 驱动(继承 DaqAbstract) |
Snet.Sim |
仿真驱动(继承 DaqAbstract) |
Snet.TEP |
TepMaster 集成(继承 DaqAbstract) |
9. CoreUnify 实例生命周期
1. 实例创建
InstanceAsync(param)
├── param 为 null?→ Activator.CreateInstance<D>()
├── semaphore.WaitAsync()
├── objList.TryGetValue(param) → 精确匹配?返回现有实例
├── kvp.Key.Comparer(param) → 深度匹配?返回现有实例
├── CreateInstance(param) → ConstructorInfo.Invoke()
├── objList.TryAdd(param, inst) → 添加到池中
└── semaphore.Release()
2. 操作
BegOperateAsync() → TimeHandler.StartRecord()
... 业务逻辑 ...
EndOperateAsync(status, msg, data, ex)
├── TimeHandler.StopRecord() → 计算 runTime
├── 格式化本地化日志消息
├── 如果 !status:通过 Serilog 调用 LogHelper.ErrorAsync()
└── 返回 OperateResult(status, msg, runTime, data)
3. 释放
DisposeAsync()
├── [子类清理:WAOff()、Off(true)]
├── UnregisterLanguageEvent() → -= 缓存的委托
├── objList.Remove(basics) → 从池中移除
└── GC.SuppressFinalize()
10. 接口摘要
| 接口 | 定义位置 | 实现类 | 关键成员 |
|---|---|---|---|
IGetParam |
Snet.Model |
CoreUnify |
GetParam、GetAutoAllocatingParam |
ICreateInstance |
Snet.Model |
CoreUnify |
CreateInstance<T>、CreateInstance(string json) |
IEvent |
Snet.Model |
CoreUnify |
OnDataEvent、OnInfoEvent、OnLanguageEvent(+ async) |
ILog |
Snet.Model |
CoreUnify |
LogOperateSet、LogOperateGet |
ILanguage |
Snet.Model |
CoreUnify |
GetLanguageValue、SetLanguage、GetLanguage |
IDaq |
Snet.Model |
DaqAbstract |
继承 IOn、IOff、IRead、IWrite、ISubscribe、IGetStatus、IWA、IGetObject |
IMq |
Snet.Model |
MqAbstract |
继承 IOn、IOff、IProducer、IConsumer、IGetStatus |
ICommunication |
Snet.Model |
CommunicationAbstract |
On、Off、Send、SendWait、GetBaseObject、GetStatus |
ICommunicationService |
Snet.Model |
CommunicationServiceAbstract |
On、Off、Send(byte[],string[])、Send(byte[],string)、Remove、GetBaseObject、GetStatus |
相关文档
- Snet.Docs -- API 参考:
F:/Snet/Web/Snet.Docs/wwwroot/docs/api/ - Snet.Model:
F:/Snet/Shunnet/Snet/Snet.Model/-- 接口、枚举、数据模型 - Snet.Log:
F:/Snet/Shunnet/Snet/Snet.Log/-- 基于 Serilog 的日志基础设施 - Snet.Utility:
F:/Snet/Shunnet/Snet/Snet.Utility/-- 共享工具类 - 单个驱动文档: 每个
Snet.{Vendor}包均包含自己的 README
