当前位置: 首页 > news >正文

MQTT CS架构设计

目录

1.项目背景

2.项目下载

3.架构介绍

4.细节讲解

4.1 消息接收处理

4.2 网关处理

4.3 接口方法定义

4.4 IOC容器加载 服务组件/客户端组件

4.5 数据库操作


1.项目背景

项目是针对线体项目,进行设计线体流程管理系统,包含人工工位(20个工位以上)和串联的单机设备(5台以上)
管理系统负责工位数据的收集,以及流程的控制,人员的操作响应等

拓扑图

2.项目下载

下载链接:https://download.csdn.net/download/rotion135/93011359

3.架构介绍

设计模式以 MQTT为主要通讯协议,同时支持与PLC的ModbusTCP,测试设备的RS232通讯等
采用CS的设计框架,客户端与服务端是多对一的模式。 架构设计上也支持多对多的模式,就是数据同步上需要重新设计一下


接口调用参考了MVC的模式实现,以定义控制器的方式,采用反射将接口与主题绑定,决定请求路径的执行与返回

4.细节讲解

解决方案目录

4.1 消息接收处理

MQTT服务,接收到客户端的请求后,在下面的事件中响应处理


/// <summary>
/// 消息接收
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
private Task MqttServer_InterceptingPublishAsync(InterceptingPublishEventArgs arg)

获取ClientId,知道来源客户端

再获取主题与携带的参数

把主题和参数都传入到 网关API 中处理,再等待网关回复数据,再通过主题返回给客户端

4.2 网关处理

网关收到消息后,根据主题路径,获取需要调用的目标方法,通过反射的机制实现方法调用,再返回结果。参数都是Json的数据结构,目标方法是空参数的话,传入的参数就需要时空Json对象,即"{}"

/// <summary> /// 请求操作 /// </summary> /// <param name="toptic">主题内容</param> /// <param name="param">参数</param> /// <returns></returns> public static async Task<string> RequestOperation(string clientId, string toptic, object param) { string msgModel = "{}"; try { //根据主题获取请求路径 // 1.根据主题获取请求路径/反射所需信息 var item = TopticCache.TopticCaches.Find(x => x.RequestToptic == toptic); if (item == null) { return msgModel; } // 2.将入参JSON字符串转为JObject(核心:方便根据参数名取值+自动类型转换) string paramJson = param?.ToString() ?? "{}"; JObject paramJObj = JObject.Parse(paramJson); // 3.反射:拼接完整类名【命名空间.类名】,获取类的Type对象 string fullClassName = $"{item.NameSpace}.{item.Controller}"; Type targetClassType = AppDomain.CurrentDomain.GetAssemblies() .Select(asm => asm.GetType(fullClassName)) // 从每个程序集中获取类型 .FirstOrDefault(type => type != null); // 取第一个非空的匹配类型 //Type targetClassType = Type.GetType(fullClassName); if (targetClassType == null) { return msgModel; } // 4.创建类的实例(如果是单例/注入的服务,这里可以替换为IOC容器获取实例) object classInstance = Activator.CreateInstance(targetClassType); // 5.反射:获取类中指定的异步方法对象 MethodInfo targetMethod = targetClassType.GetMethod( item.Method, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); if (targetMethod == null) { return msgModel; } // 6.核心:解析JSON参数,匹配目标方法的入参,生成参数数组 ParameterInfo[] methodParams = targetMethod.GetParameters(); object[] invokeParams = new object[methodParams.Length]; for (int i = 0; i < methodParams.Length; i++) { var paramInfo = methodParams[i]; // 从JSON中根据【参数名】取值,兼容参数名大小写不一致问题 JToken paramValue = paramJObj.GetValue(paramInfo.Name, StringComparison.OrdinalIgnoreCase); if (paramValue == null || paramValue.Type == JTokenType.Null) { // 无传参时,赋值默认值 invokeParams[i] = paramInfo.HasDefaultValue ? paramInfo.DefaultValue : null; } else { // 自动类型转换:JSON值 转为 方法入参的实际类型 invokeParams[i] = paramValue.ToObject(paramInfo.ParameterType); } } //赋值ClientId (classInstance as BaseAPIController).ClientId = clientId; // 7.核心:反射调用【异步方法】并await执行,获取返回结果 var methodResult = targetMethod.Invoke(classInstance, invokeParams); // 异步方法必须await,获取Task的实际返回值 if (methodResult is Task realTask) { await realTask; // 通过反射获取Task<T>的Result属性,拿到真实返回数据 var resultProperty = realTask.GetType().GetProperty("Result"); if (resultProperty != null) { var realData = resultProperty.GetValue(realTask); // 8.将方法返回值 赋值给泛型返回对象 if (realData != null) { msgModel = JsonConvert.SerializeObject(realData); } } } return msgModel; } catch (Exception ex) { MsgModel err = new MsgModel(false, MsgErrorType.Internal_Error, ex.Message); return JsonConvert.SerializeObject(err); } }

4.3 接口方法定义

接口类都需要继承基类 BaseAPIController

特性APIRoute 定义主题的前部分

方法,再用特性定义主题的后半部分

加起来,访问目标方法的主题就是:

后面再填充各个客户端的ClientId,就能请求方法了

4.4 IOC容器加载 服务组件/客户端组件

服务主程序 和 客户端主程序,运行起来时,通过配置参数来决定IOC容器加载的引用项目

服务端:

客户端:

4.5 数据库操作

此处定义数据库的操作方法,定义实体,定义数据模型

数据库ORM使用 SqlSugar,

我的这篇文章有详细介绍:

SqlSugar 数据库操作通用类设计_c# sqlsugar通用类-CSDN博客

Domain里边定义访问数据库的方法,增删查改等

如果有实现缓存的,先从缓存中获取。

DBControl 定义了数据库初始化的代码,包含生成数据库,生成表,添加索引,以及上线后新增字段等功能

http://www.jsqmd.com/news/1067700/

相关文章:

  • 制造业获客困局破局之道:知识图谱重构AI时代B2B决策链路
  • 设计模式——工厂类设计模式(AI回答)
  • 告别图片加载等待:ImageGlass极速图像查看器全面解析
  • PicklingError: Can‘t pickle <class ‘trl.trainer.sft_config.SFTConfig‘>: it‘s not the same object as
  • Python爬虫实战:政府年度统计公报PDF批量爬取与文本解析系统(附完整代码)
  • 零基础入门GIT
  • 8大主流网盘直链一键获取:告别限速困扰的终极解决方案
  • 如何用JPEXS Free Flash Decompiler拯救你珍贵的Flash数字遗产?
  • 出海企业SSL证书怎么选?Digicert、Sectigo 真实使用体验分享
  • API 是什么?给不懂技术的小白:点菜、快递和“软件服务员”
  • 西方数学历史及关键时间节点和人物
  • 昇腾计算架构CANN图像视觉算子库中ops-cv仓库的目标检测融合算子设计与开放神经网络交换格式插件扩展接入流程及算子自动生成工具使用方法全面技术解读
  • 如何5分钟找出微信单向好友:一键检测谁删除了你的完整指南
  • 技术传输对象的数据封装与传输
  • 从零构建国际宏观数据爬虫:世界银行与IMF数据自动化采集指南
  • 【免费领源码】基于PHP框架的文旅资源展示与智能推荐平台|库存管理/订单发货/车辆管理完整项目
  • AUTOSAR 完全指南:从入门到实践
  • 2026年广东TikTok直播带货课程服务方参照:五家机构定位与能力分析
  • 深度学习中的神经网络设计与优化
  • 论文数据被 Nature 子刊引用是什么体验?谈谈科研数据的 “隐性含金量”
  • MySQL 索引类型选择指南
  • GB/T 4857.17-2017 标准科普|运输包装试验大纲通用规则
  • 云南高原监控工程技术纪实:本土服务商云南凯尊科技全维度解析
  • Gemini 3.5 图表 + 文字混合文档信息融合技术解析:原生多模态架构、统一 Token 序列化与工程实践
  • 多账号浏览器选型:个人多开和团队协作的技术检查清单
  • 什么是涌现?
  • 为什么Redis的SETNX命令可以实现分布式锁?
  • 全域核销领跑全国足浴行业:索易软件四大平台官方直连,数字化实力断层领先
  • 事件驱动化技术事件溯源与命令查询职责分离模式
  • 昇腾计算架构集合通信库的拓扑感知全规约算法实现与多卡分布式训练梯度同步通信调度优化及链路故障自动检测恢复容错机制深度技术解析