C#远程数据采集插件化解析框架设计:如何兼容 Modbus RTU/SCDMA 多种通信协议?
2026/6/26 5:27:14 网站建设 项目流程

远程监控系统中,很多设备都有自己的通讯协议,如何做的兼容这些不同的协议?我们系统采用的的方案是把解析逻辑做成插件,每种协议一个 DLL,在后台进行配置,解析的时候自动匹配到合适的解析器。增加协议的时候,不用改代码,只要根据手册开发对应的 DLL 。


一、背景

1.1 业务场景

协议类型应用场景数据格式
RTU 协议抽油机控制器自定义帧结构
Modbus RTU标准工业设备功能码 + 寄存器
SCDMA水表/流量计188 协议变种

传统做法是为每种协议硬编码解析逻辑,耦合重、难维护,加新协议要改核心代码,还没法热更新,必须重启服务。

1.2 设计目标

  • 插件化:每种协议独立 DLL,互不影响
  • 配置驱动:数据库配置启用/禁用协议
  • 热加载:运行时动态加载,无需重启
  • 统一接口:所有协议实现同一接口

二、核心架构

2.1 IAnalytical 接口

所有协议解析器实现IAnalytical接口:

// IAnalytical.cspublicinterfaceIAnalytical{// 协议标识stringAgreementId{get;set;}// 输入/输出字段列表(用于配置界面)List<string>InputNameList{get;}List<string>OutputNameList{get;}// 生命周期管理voidStart(GetDeviceMonitord);voidStop();// 核心方法boolJudgeAnalytical(...);// 协议识别Dictionary<string,string>AnalyticalData(...);// 数据解析stringCreateCommands(...);// 命令生成stringMaskSQL(...);// SQL 生成}

2.2 协议识别机制

系统收到原始数据后,遍历所有已加载的协议,找到匹配的解析器:

// HaoPuServer.cs - LogicAnalytical()privatevoidLogicAnalytical(refReceivedDataEventArgse){foreach(IAnalyticalanalyticalinthis.Agreement.Values){if(analytical.JudgeAnalytical(e.Clientid,e.RequestHex,refstartIndex,refstartLength,refisValid,refrtuAddress,refcode,refextend,refdeviceId,refdeviceName,refmonitorId,refmonitorName,referrorMsg,this.Config.monitorMana,this.Config.deviceMana)){// 找到匹配的协议,跳出循环e.Agreementid=analytical.AgreementId;break;}}}

每个协议的JudgeAnalytical()方法自己判断数据是否属于自己,匹配成功后break,返回AgreementId,后续解析用对应的协议实例。


三、动态加载

3.1 Agreement 配置表

协议信息存在数据库Agreement表里:

字段说明示例
id协议 IDDLL001
dllpathDLL 文件路径Drive\Rrs.CyyRtu.dll
classname类全名Rrs.CyyRtu.Rtu
desc描述标准 RTU 协议
status启用状态True/False

3.2 运行时加载

系统启动时遍历Agreement表,动态加载启用的协议:

// HaoPuServer.cs - AgreementInit()privateboolAgreementInit(Agreemente){try{stringstartupPath=Application.StartupPath;// 1. 从 DLL 文件加载程序集Assemblyassembly=Assembly.LoadFile(startupPath+"\\"+e.DllPath);// 2. 创建协议解析器实例IAnalyticalanalytical=(IAnalytical)assembly.CreateInstance(e.ClassName);// 3. 设置协议 IDanalytical.AgreementId=e.ID;// 4. 启动协议(注册回调)analytical.Start(newGetDeviceMonitor(this.GetDeviceMonitor));// 5. 加入协议字典this.Agreement.Add(analytical.AgreementId,analytical);returntrue;}catch(Exceptionex){// 记录错误日志returnfalse;}}

3.3 协议字典

加载后的协议存在字典里,键是AgreementId

// HaoPuServer.csprivateDictionary<string,IAnalytical>Agreement;

O(1) 查找,支持运行时增删,配合 lock 保证线程安全。


四、协议实现示例

4.1 Modbus 协议(Moudbs)

// Rrs.Moudbs/Moudbs.cspublicclassMoudbs:IAnalytical{privatestringagreementId;publicstringAgreementId{get{returnthis.agreementId;}set{this.agreementId=value;}}// 输出字段列表(用于配置界面下拉框)publicList<string>OutputNameList{get{returnnewList<string>(newstring[]{"小数","保留小数","冲程","冲次","位移包","载荷","电流","电压","有功功率","无功功率","功率因数","累计电量","压力","年月日时分"});}}// 协议识别:检查功能码是否为 0x03(读保持寄存器)publicboolJudgeAnalytical(...){intcode=...;if(code==0x03){returntrue;}returnfalse;}// 数据解析publicDictionary<string,string>AnalyticalData(Deviced,Monitorm,stringresponsehex,objectextend){// 解析 Modbus 响应数据// 返回字段名 -> 字段值的字典}}

4.2 SCDMA 协议(水表)

// Rrs.SCDMA/SCdma.cspublicclassSCdma:IAnalytical{publicList<string>OutputNameList{get{returnnewList<string>(newstring[]{"小数","井站类型","设备厂家","通讯方式","通讯协议","波特率","数据位","停止位","188电压","188流量","188水表状态","188单位"});}}// 协议识别:检查是否为 188 协议帧publicboolJudgeAnalytical(...){// 解析 188 协议帧头// 匹配则返回 true}}

4.3 RTU 协议(抽油机)

// Rrs.CyyRtu/Rtu.cspublicclassRtu:IAnalytical{publicList<string>OutputNameList{get{returnnewList<string>(newstring[]{"小数","保留小数","冲程","冲次","位移包","载荷","电流","电压","曲柄销子退扣","测试类型","故障停井选项"});}}}

五、配置界面

5.1 协议管理

配置界面通过FormConfig做协议管理:

// FormConfig.cs - 加载协议配置privatevoidLoadDataConfig(){this.agreementMana=newAgreementMana(this.IData);// ... 加载其他配置}// 启用/禁用协议privatevoidActiveConfig(){Agreementagreement=(Agreement)this.bindingSource1.Current;if(!agreement.Status){// 启用协议if(this.ActiveAgreeEvent(agreement)){agreement.Status=true;}}else{// 禁用协议if(this.ActiveAgreeEvent(agreement)){agreement.Status=false;}}}

5.2 动态字段绑定

配置界面根据协议的InputNameListOutputNameList动态生成下拉框:

// FormConfig.csIAnalyticalanalytical=(IAnalytical)Assembly.LoadFile(startupPath+"\\"+agreement.DllPath).CreateInstance(agreement.ClassName);// 绑定输入字段下拉框DataGridViewComboBoxColumncol1=(DataGridViewComboBoxColumn)this.dataGridView1.Columns["ModifiedOutput"];col1.DataSource=analytical.InputNameList;// 绑定输出字段下拉框DataGridViewComboBoxColumncol2=(DataGridViewComboBoxColumn)this.dataGridView1.Columns["ModifiedOutput"];col2.DataSource=analytical.OutputNameList;

新增协议不用改配置界面代码,字段列表由协议 DLL 自己定义,配置界面和协议解耦。


六、完整数据流

关键词:插件化架构,协议解析,多协议适配,工业物联网


本文基于实际项目经验编写,代码已脱敏处理。如需完整源码或技术咨询,欢迎私信或评论交流。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询