十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于.NET8.0的工业组态多协议通信服务架构与工程实践

基于.NET8.0的工业组态多协议通信服务架构与工程实践 这次我们来拆一个很实用的工程落地主题基于 .NET8.0 的工业组态通信与多协议通信配置项目代号就叫B1421。它并不是一个只会在 PPT 里出现的“概念框架”而是一套可以跑在 Windows 工控机、Linux 边缘网关、Docker 容器里的数据采集与下发服务。核心要解决的是工业现场最头疼的问题——现场设备来自不同厂商有的走 Modbus TCP有的走 Modbus RTU有的用 OPC UA 或 S7 协议上层组态软件要拿到统一的数据必须有一个中间层把所有协议收敛到同一个“点表模型”里。B1421 这类方案的关注点不是单纯的“串口收发”或“socket 连接”而是几个更工程化的问题协议插拔新增一种设备类型时能不能不改动采集主流程只增加一个驱动组件点表配置化PLC、仪表、传感器下面的每一个变量是否可以通过 JSON/数据库配置而不是写死在代码里批量与调度上千个点位是否支持按设备批量读取、统一轮询、异常数据补偿下游对接采集到的最新值能否通过 MQTT、REST API、OPC UA Server 等方式稳定地送给组态画面、MES 或云端.NET8.0 在其中的优势很明显它是 LTS 版本支持到 2026 年 11 月跨平台能力成熟同一个服务可以直接部署到 Linux 工业网关异步 I/O 和后台任务模型非常适合“多路设备并发采集”这种场景。下面这篇文章不写空框架而是用一套可以复用的“最小可运行通信服务”来拆解 B1421 的架构、环境、配置方式和验证思路。代码部分以工程骨架为主现场设备地址、点位区间、协议库版本需要按实际环境替换但整体设计和排查思路是通用的。1. B1421 核心能力速览先把 B1421 的能力边界和门槛列出来方便判断它适不适合你的项目场景。能力项说明项目类型工业组态通信中间件 / 多协议数据采集服务基础框架.NET8.0LTS 版本跨平台部署典型协议Modbus TCP、Modbus RTU、OPC UA、S7、MQTT 消息上送设备接入方式网口、串口、网关代理按现场设备选型配置方式JSON 配置 / 数据库点表通道与点位分离调度能力多设备并发轮询、批量读取、断线重连、失败补偿数据出口日志、REST API 查询、MQTT 转发、OPC UA Server 扩展运行平台Windows 10/11、Windows Server、Linux、Docker推荐硬件x86_64 工控机或边缘网关内存 4GB 以上CPU 2 核以上启动方式dotnet run、systemd、Docker Compose是否支持 API可以内置 REST API 暴露实时点位值是否支持批量任务支持按通道批量读取并异步发布适合场景组态软件数据接入、跨协议数据汇总、边缘数据网关、MES 数据源需要注意的上位条件是协议驱动是工程实现中最消耗时间的部分。B1421 提供的是一套“调度框架 配置模型 服务生命周期”真正的 Modbus 驱动、OPC UA 客户端、S7 客户端通常来自第三方库或自研组件。把协议的差异封装进IDeviceDriver接口之后上层调度逻辑、点表缓存、发布逻辑就可以保持稳定。2. 适用场景与使用边界先明确 B1421 解决的是什么问题。假设一个工厂有 20 台 PLC10 台走 Modbus TCP5 台走 Modbus RTU还有 3 台通过 OPC UA 对外提供数据组态画面需要在一个画面里同时看到所有设备的关键参数。传统做法是让组态软件逐台配置驱动维护量很大而且当网络发生抖动时某一个通道卡死可能影响整条采集链路。B1421 的做法是在组态和现场设备之间增加一个“通信服务层”由它统一负责建立连接、轮询点位、缓存数值再以统一 API 或消息格式把数据给到上层。这个方案适合以下几类工程师正在做 SCADA/HMI 上位机需要把多种 PLC 数据做成统一接口的。在做设备数据采集上云需要 Modbus/MQTT 转换的边缘网关开发。想把重复的“连接设备-读点-转换-上报”流程沉淀成可复用服务。需要把传统 WinForm 组态程序迁移到 .NET 生态希望保留工业协议接入能力。不适合的场景也要说清楚实时控制要求极高的情况不推荐绕一层软件中间件。比如伺服轴联动、运动控制插补这类场景应该走 PLC 之间的硬实时总线或专用运动控制器不要在普通 TCP 采集链路里做位置闭环。已有成熟 DCS/SCADA 且点位规模达到数十万点时自研通信层的前期压力会比较大建议优先评估商业组态软件或成熟工业网关。如果只是偶发采集几个温度值并不需要引入完整调度框架直接写一个 Modbus 控制台程序更轻量。安全与合规边界同样不能忽略。现场设备往往承载生产过程任何写操作都要使用测试台架验证后再灰度接入。采集点位如果涉及生产运行数据要遵守企业数据管理制度不能把未经授权的内容直接暴露到公网。后面章节涉及 MQTT、REST API 时也要注意访问控制、端口隔离和身份认证。3. B1421 多协议通信架构设计B1421 在多协议通信上采用的并不是“一个设备一个独立线程”的笨办法而是抽象出四层结构。3.1 通信服务分层模型大致分层如下层次职责典型组件配置层定义通道、设备、点位、协议类型、轮询间隔appsettings.json / DB 点表驱动层每种工业协议封装为一个驱动ModbusTcpDriver、OpcUaDriver调度层管理采集任务、断线重连、批量执行CollectWorker 后台服务发布层把点位值传给组态、MES、云平台REST API、MQTT Publisher这个结构的优点是点表配置和驱动实现解耦。新增一台设备不需要修改调度器只需要在配置文件中新增一个通道和一批点位新增一种协议时只需要实现驱动接口并注册到驱动路由表。3.2 配置驱动通道与点位分离工业组态通信中“点表”是核心。一个点可以理解为现场设备的一个变量它有唯一标识、设备归属、寄存器地址、数据类型和量程转换信息。通道则表示一条与设备通信的链路里面包含协议类型、IP、端口、串口号、波特率、轮询周期。B1421 示例中把配置模型拆成两层以 JSON 为例通道定义写这个位置{ Channels: [ { DeviceId: PLC_MAIN_01, Protocol: ModbusTcp, Endpoint: 127.0.0.1:502, SlaveId: 1, PollIntervalMs: 1000, BatchSize: 10 }, { DeviceId: ENERGY_METER_01, Protocol: ModbusRtu, PortName: COM3, BaudRate: 9600, DataBits: 8, Parity: None, StopBits: One, PollIntervalMs: 2000 } ] }点位单独维护。生产环境点位可能放在 SQLite 或 SQL Server 中方便组态页面动态增删这里用 JSON 数组做示例{ TagGroups: [ { DeviceId: PLC_MAIN_01, Tags: [ { Id: TEMP_01, Name: 反应釜温度, Address: 40001, DataType: Float, Scale: 0.1, Offset: 0, IsWritable: false }, { Id: PRESS_01, Name: 管道压力, Address: 40003, DataType: Int16, Scale: 0.01, Offset: 0, IsWritable: false } ] } ] }配置驱动带来的收益很直接场景变化时多数情况下只需要调整配置不用发布新程序。这也是 B1421 名称里“多协议通信配置”的价值所在。3.3 点表对象模型在 .NET 代码中点位对象建议这样建模public class TagItem { public string Id { get; set; } public string Name { get; set; } public string DeviceId { get; set; } public string Address { get; set; } public string DataType { get; set; } public double? Scale { get; set; } public double? Offset { get; set; } public bool IsWritable { get; set; } public DateTime LastUpdate { get; set; } public object RawValue { get; set; } }Scale 和 Offset 两个字段很关键。很多仪表内部是原始整型值比如温度寄存器返回 325实际温度是 32.5℃此时 Scale0.1 就能在采集层完成量程转换。这样组态画面拿到的已经是工程值不需要在上位机再处理一遍。4. 环境准备与前置条件开始部署前先确认运行环境满足这些条件。4.1 操作系统与运行时项目建议操作系统Windows 10/11、Windows Server 2019、Ubuntu 20.04/22.04.NET 版本.NET SDK 8.0.x 或 .NET Runtime 8.0.x数据库轻量场景用 SQLite中大规模用 SQL Server / PostgreSQL容器环境Docker Engine Docker Compose网络要求与 PLC/仪表在同一个二层网络或能路由到达串口要求Modbus RTU 设备需要物理串口或 USB 转串口使用命令确认 .NET 环境是否已安装dotnet --version dotnet --list-runtimes如果机器上没有 .NET8.0可以安装 .NET SDK 或运行时安装完成后重新打开终端让 PATH 生效。4.2 CPU 与内存占用的边界纯数据采集服务不是高算力场景。以几百个点位、1 秒轮询为例2 核 CPU、4GB 内存的工控机通常足够。但如果点位规模到上万点同时开启很多 MQTT 消息发布内存就需要扩大到 8GB 以上并且要关注网络队列积压。真实占用取决于协议类型和第三方库实现。点位数量与轮询频率。是否频繁执行大批量 JSON 序列化。是否保留历史数据缓存。建议部署之后用dotnet-counters跟踪内存与 CPU再决定是否调大并发度。4.3 端口规划B1421 会占用以下类别的端口采集侧Modbus TCP 默认 502S7 默认 102OPC UA 常见 4840。发布侧REST API 可指定 8080MQTT broker 通常在 1883。同一台机器上如果已有组态软件占用 502 端口需要改设备侧的端口映射或把通信服务部署在独立网关上。5. .NET8.0 多协议采集服务核心实现下面用一套极简但可运行的代码骨架展示 B1421 的核心调度逻辑。这个骨架假定你已经把配置模型读到了B1421Options中。5.1 定义驱动接口所有工业协议最终都抽象成三个操作连接、读取、写入。public interface IDeviceDriver { string Protocol { get; } Task ConnectAsync(DeviceChannel channel, CancellationToken ct); TaskListTagValue ReadAsync( IReadOnlyListTagItem tags, CancellationToken ct); Task WriteAsync( string tagId, object value, CancellationToken ct); Task CloseAsync(); }TagValue是采集结果的数据载体简单定义可以这样写public class TagValue { public string TagId { get; set; } public object Value { get; set; } public bool Success { get; set; } public string Error { get; set; } public DateTime Timestamp { get; set; } }5.2 创建驱动路由与注册调度器不关心具体协议只关心一个DeviceId对应哪个驱动。因此需要一个路由表public sealed class DriverRouter { private readonly Dictionarystring, IDeviceDriver _drivers new(StringComparer.OrdinalIgnoreCase); public void Register(IDeviceDriver driver) { _drivers[driver.Protocol] driver; } public IDeviceDriver Get(string protocol) { if (_drivers.TryGetValue(protocol, out var driver)) { return driver; } throw new NotSupportedException($未注册的协议: {protocol}); } }模拟 Modbus TCP 驱动时只要实现IDeviceDriver并完成协议字节组包、解析。驱动注册放到启动代码里using B1421.Host.Drivers; using B1421.Host.Router; var builder Host.CreateApplicationBuilder(args); builder.Services.ConfigureB1421Options(options builder.Configuration.GetSection(B1421).Bind(options)); builder.Services.AddSingletonDriverRouter(); builder.Services.AddSingletonModbusTcpDriver(); builder.Services.AddSingletonCollectWorker(); builder.Services.AddHostedService(sp sp.GetRequiredServiceCollectWorker()); var host builder.Build(); await host.RunAsync();CollectWorker同时是单例和后台服务可以持有最新点表缓存。5.3 核心采集循环最核心的调度逻辑是一个BackgroundService它按设备通道做轮询。建议采用Channel或SemaphoreSlim控制并发防止某台设备无响应导致整体阻塞。以 Modbus TCP 为例一个典型的读取流程是遍历配置找到要采集的通道。把该通道下的点位按 BatchSize 分片。每片并发发起一次读取请求。读取成功后更新点表缓存并写入消息队列。循环到下一轮前延迟 PollIntervalMs。这里给一个非常简化的版本public sealed class CollectWorker : BackgroundService { private readonly B1421Options _options; private readonly DriverRouter _router; private readonly ILoggerCollectWorker _logger; public CollectWorker( B1421Options options, DriverRouter router, ILoggerCollectWorker logger) { _options options; _router router; _logger logger; } protected override async Task ExecuteAsync(CancellationToken ct) { var channels _options.Channels; while (!ct.IsCancellationRequested) { foreach (var channel in channels) { try { var driver _router.Get(channel.Protocol); await driver.ConnectAsync(channel, ct); var tags _options.TagGroups .Where(g g.DeviceId channel.DeviceId) .SelectMany(g g.Tags) .ToList(); // 按批读取模拟驱动内部按寄存器连续块优化 var chunks tags.Chunk(channel.BatchSize 0 ? channel.BatchSize : 10); foreach (var chunk in chunks) { var result await driver.ReadAsync(chunk.ToList(), ct); foreach (var item in result) { // 这里可以写入实时点表或发布到 MQTT _logger.LogInformation({TagId} {Value}, item.TagId, item.Value); } } } catch (Exception ex) { _logger.LogError(ex, 通道 {DeviceId} 采集失败, channel.DeviceId); } } await Task.Delay(1000, ct); } } }真实环境里这套代码还需要补充连接状态判断避免每轮都重新握手。寄存器连续块合并例如 40001-40010 连续 10 个寄存器可以一次读完而不是逐点读取。写操作的权限校验防止误操作现场设备。点位值变化检测没变化的点位不必重新发布。6. 多协议通信配置与启动服务B1421 的配置文件建议放在appsettings.json中启动时通过 Host 的配置系统加载。6.1 一个包含 Modbus 与 MQTT 上送的配置示例{ Logging: { LogLevel: { Default: Information, B1421.Host.CollectWorker: Debug } }, B1421: { Channels: [ { DeviceId: PLC_MAIN_01, Protocol: ModbusTcp, Endpoint: 127.0.0.1:502, SlaveId: 1, PollIntervalMs: 1000, BatchSize: 20 } ], TagGroups: [ { DeviceId: PLC_MAIN_01, Tags: [ { Id: TEMP_01, Name: 反应釜温度, Address: 40001, DataType: Float, Scale: 0.1, IsWritable: false } ] } ], Mqtt: { Endpoint: 127.0.0.1:1883, ClientId: b1421-collector, TopicPrefix: factory/b1421/data } } }配置读取建议使用强类型绑定public sealed class B1421Options { public ListDeviceChannel Channels { get; set; } new(); public ListTagGroup TagGroups { get; set; } new(); public MqttOptions Mqtt { get; set; } }这样可以避免业务代码里到处用IConfiguration[xxx]拿字符串类型安全也能更好保证。6.2 启动服务本地调试时运行cd src/B1421.Host dotnet run发布到生产目录时使用dotnet publish -c Release -o out cd out dotnet B1421.Host.dllLinux 下做成 systemd 服务需要写一个.service文件[Unit] DescriptionB1421 Industrial Communication Service Afternetwork-online.target [Service] WorkingDirectory/opt/b1421 ExecStart/usr/bin/dotnet /opt/b1421/B1421.Host.dll Restartalways RestartSec5 EnvironmentASPNETCORE_ENVIRONMENTProduction [Install] WantedBymulti-user.target启动后用journalctl -u b1421 -f可以查看服务日志。6.3 Docker Compose 部署参考如果 B1421 需要和 MQTT Broker如 EMQX一起部署可以用一个 Compose 文件管理version: 3.8 services: b1421: image: registry.example.com/b1421-host:latest container_name: b1421-host network_mode: host environment: - ASPNETCORE_ENVIRONMENTProduction volumes: - ./appsettings.json:/app/appsettings.json:ro - ./logs:/app/logs restart: unless-stoppednetwork_mode: host在工业网关里很常见因为设备往往分布在多个网卡网段桥接网络会增加 NAT 配置复杂度。7. 数据出口REST API 与 MQTT 推送采上来的数据最终要给组态画面、MES 或云平台。B1421 推荐的出口包括 REST API 实时查询和 MQTT 主题发布两种。7.1 用 REST API 查询实时点位值内置一个极简 ASP.NET Core 接口可以直接查看所有点位的最新值app.MapGet(/api/tags, (CollectWorker worker) { var snapshot worker.GetSnapshot(); return Results.Ok(snapshot); }); app.MapGet(/api/tags/{id}, (string id, CollectWorker worker) { var tag worker.GetTag(id); return tag is null ? Results.NotFound() : Results.Ok(tag); });调用示例curl http://127.0.0.1:8080/api/tags/TEMP_01响应结构大致是{ tagId: TEMP_01, name: 反应釜温度, value: 32.5, quality: 192, timestamp: 2025-02-01T10:30:00.000Z }这里包含 quality 是很有价值的做法组态画面可以判断当前值是否是一个可信任的新鲜数据。7.2 MQTT 批量发布如果现场已经有 IoT 平台或组态画面订阅 MQTTB1421 可以把周期性采集结果发布到主题factory/b1421/data。发布内容按设备分批组织{ deviceId: PLC_MAIN_01, timestamp: 2025-02-01T10:30:00.000Z, values: [ { tagId: TEMP_01, value: 32.5, quality: 192 } ] }数据是否每次都发建议由“值变化”判断来过滤。如果温度 30 秒内没有变化就没必要每秒发一条相同数据。发布频率要根据下游消费能力设计否则 MQTT Broker 会堆积大量无用消息。8. 资源占用与性能观察工业采集服务通常在工控机上 7x24 小时运行性能和稳定性比“功能跑通”更重要。8.1 最值得关注的三项指标指标观察方法合理状态CPU 占用dotnet-counters monitor --process-id pid稳定运行后波动不大无持续 80% 以上内存占用docker stats或任务管理器不出现持续增长排除内存泄漏消息积压MQTT 或内部队列长度队列长度不应随时间无限增长8.2 采集链路性能分析影响性能的主要因素不是服务本身而是“协议交互方式”。Modbus 这类协议读取速度和寄存器布局关系很大。连续寄存器读取一次可以拿到一批点位如果点位分散在不同地址区间就需要多次请求。B1421 的最佳实践是把点位按寄存器地址排序再按连续区间分片。这样原本可能需要 100 次请求才能采完的点表可以压缩到 20 次以内。OPC UA 和 S7 有各自的批量读取接口不要在应用层做“逐点读取”再拼接那样会把协议栈的优势完全浪费掉。8.3 降低资源占用的方法调大BatchSize减少协议交互次数。对不同实时性要求的点位设置不同轮询间隔。温度点 5 秒采一次电能表 30 秒采一次可以显著降低总吞吐。关闭不必要的调试日志。LogInformation在高频点位采集下会产生非常大的日志量。发布数据时启用值变化检测合并连续相同值。如果点位数量很大考虑引入System.Threading.Channels做生产者-消费者解耦避免采集线程和网络发布线程互相拖累。8.4 端口冲突与进程残留运行多套实例时要检查端口占用netstat -ano | findstr :8080Linux 下使用ss -lntp | grep 8080如果服务异常退出后端口还被占用需要结束残留进程再启动。9. 功能测试与效果验证接入现场设备前建议先按下面的顺序做一轮完整功能测试。9.1 测试环境准备准备一台 Modbus TCP 模拟从站比如 Modbus Slave 工具或基于 Python 的 pymodbus 模拟器。准备一台 MQTT Broker本机可以用 EMQX 或 Mosquitto。在模拟从站中设置寄存器地址 40001、40003写入测试值。9.2 验证步骤测试项操作预期结果服务启动dotnet run日志输出通道连接成功点位读取查看日志或/api/tags/TEMP_01返回模拟器中的最新值值变化更新修改模拟器寄存器值服务日志或接口返回新值断线重连关闭模拟器端口再开启服务不退出恢复后继续采集MQTT 发布订阅factory/b1421/data主题能收到设备点位 JSON批量点位配置 100 个连续寄存器点位在批处理日志中看到分批读取完成写操作测试在测试台架调用写接口模拟器对应寄存器值改变9.3 判断成功的标准一轮测试全部通过至少要确认这几件事所有点位的值与模拟器一致。断线一段时间后服务能自动恢复不需要人工重启。长时间运行内存没有持续上涨。日志中不存在大量未捕获异常。MQTT 消息到达率稳定没有重复发布或丢点数异常。写操作必须严格使用测试台架。生产设备的写操作要增加权限令牌、操作者审计、二次确认等机制绝不能在未验证的条件下直接盲目下发。10. 常见问题与排查方法下面这份排查表覆盖 B1421 实际部署时最容易遇到的几类问题。问题现象可能原因排查方式解决方案服务启动后没有任何连接日志配置的 Endpoint 错误或网络不通用ping、Test-NetConnection检查设备端口修正 IP/端口确认工控机与设备在同一网络Modbus 读取超时点位地址不连续请求次数过多抓协议报文看每次请求间隔按连续寄存器分片调大批次数串口采集失败串口号、波特率或校验位配置错误用串口工具测试闭环用System.IO.Ports列出可用串口再核对设备参数数据一直不更新从站设备响应异常数据质量位错误查看驱动返回的 quality 字段分析错误码检查从站配置MQTT 收不到消息Broker 地址或 Topic 不一致用 MQTTX 订阅观察核对 ClientId、TopicPrefix内存持续增长点位缓存或日志无界用dotnet-counters观察托管堆增加缓存上限限制日志输出频率端口冲突多个服务占用同一端口netstat -ano查看占用换端口或停止无关进程写操作没有生效寄存器地址或数据类型映射错误先用模拟器写测试核对点位地址、字节序、Scale某台设备故障影响其他设备采集调度器没有做故障隔离查看日志是否出现通道级异常为每台设备单独捕获异常设置独立重试队列11. 最佳实践与合规建议从工程落地角度看B1421 应该遵循几条明确的实践原则。11.1 先做好点表再写代码工业组态通信项目里最容易晚成的不是驱动代码而是点表清晰度。做现场接入前先把设备选型表、寄存器地址表、数据类型和量程公式整理成结构化文档。每一台设备的点位都应该有唯一 ID、含义清晰的名称和设备别名。这样后期扩展到 MES、SCADA 时数据血缘是清晰的。11.2 服务端设计要“按通道隔离故障”不要把几十台设备的采集写进同一个没有异常隔离的循环里。一台 Modbus 从站断线不应该影响其他通道读取。建议每个 DeviceChannel 都拥有独立的连接状态、重试计数、熔断状态。B1421 的驱动层抽象正是为了做到这一点。11.3 写权限必须单独控制如果只是数据采集默认不开放写接口。实在需要写操作也必须做到操作人员身份验证。写操作内容审计。点位级权限控制。仅在测试环境开放全量写权限。从通信安全的角度来看凡是暴露在局域网甚至公网的 REST API、MQTT Broker都要启用身份认证和 TLS 加密。不要让现场设备数据裸奔在非受控网络上。11.4 日志、备份与回滚配置文件纳入版本管理每次变更记录 diff。日志按照天/小时滚动保留最近 30 天即可避免写满系统盘。新版本发布前保留上一个可运行包的完整备份方便快速回滚。点表变更最好通过数据库版本脚本或配置迁移工具完成不要直接在生产环境手工改 JSON。11.5 版权与授权提醒引入 Modbus、OPC UA、S7 等协议时要注意第三方 SDK 的 License。商业闭源使用与内部项目使用的授权范围不同不能随便拿开源库用于付费产品而不确认许可证。若涉及读取他人设备或平台必须获得设备所属方授权遵守平台接口协议。不要使用绕过安全机制、未经授权采集数据的方式获取设备信息。12. 总结与下一步B1421 这类“基于 .NET8.0 的工业组态通信与多协议通信配置”工程案例最值得借鉴的不是某一个协议的具体实现而是把“设备访问”收敛成一套可配置、可插拔、可观测的通信框架。你可以先把驱动接口、通道配置、点表模型和调度任务跑通再逐步把 Modbus、S7、OPC UA 的真实协议驱动接到服务里。最先要验证的功能是用一个 Modbus 模拟从站跑通“配置通道-批量读取-状态展示”的闭环。最容易踩的坑有两个一是点位地址和数据类型映射错位导致解析出无意义数值二是把串口和网络设备混在一个无隔离的调度循环里一台故障拖垮全部采集链路。下一步扩展方向可以这样考虑接入 OPC UA Server 端向组态软件提供统一数据源。增加点位历史存储把实时值按压缩周期写入到时序数据库。增加看门狗机制服务异常退出后由 systemd 或 Docker 自动拉起。把管理界面做成 Web 页面让工程人员可以在网页上新增设备、启停通道、查看点位质量。从组态通信到边缘数据平台B1421 的定位其实是一个最小但完整的工业数据底座。只要底层的驱动隔离、点表配置和消息发布设计合理后续无论是接组态画面、MES 还是云平台都只是新增一条“发布通道”的问题。读者在落地时先保证模拟环境全链路跑通再小心接入真实设备会省掉大量现场排查时间。这篇文章涉及的代码和配置都可以直接作为新工程的基础模板按实际协议库替换驱动细节即可。
返回列表