ARTICLE DETAIL

资讯详情

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

Java对接KepServerEX实现OPC UA设备数据采集的工程实践

Java对接KepServerEX实现OPC UA设备数据采集的工程实践 车间里十几台设备PLC牌子还各不相同西门子、三菱、欧姆龙混着来上位系统又要统一拿数据这应该是做工业数据采集的人都撞过的墙。我之前接一个MES项目就是这么被逼的——一台台设备用原生协议去读代码写了一堆还牵涉Modbus TCP、S7comm、MC协议来回切后来换了思路用KepServerEX把设备协议全部收编对外统一暴露OPC UA接口再写一个Java客户端去消费数据。这套东西最让我省心的地方是中间层把协议差异全屏蔽了Java端只需要盯着一种协议做。这篇文章就把我从零开始打通环境的完整过程拆开写包括架构分工、KepServerEX侧配置、Java侧订阅代码、实测踩过的坑以及从Demo走向生产的改造思路给同样在做设备数据对接的工程师做个参考。1. 架构分工为什么要把对接PLC这件事交给KepServerEX在动手写Java代码之前我先想明白了一件事OPC UA客户端和KepServerEX到底谁干谁的活。很多人第一次接触这套组合容易搞反以为Java客户端要直连PLCKepServerEX只是中间加了个壳。实际上链路是这样的设备侧PLC、数控机床、传感器通过各自的私有协议或标准协议通信采集侧KepServerEX安装在一台Windows机器上通过驱动插件去和设备群通信比如用 Siemens TCP/IP 驱动读 S7 协议用 Modbus TCP 驱动读仪表汇聚侧KepServerEX把采集到的点位统一映射成OPC UA的地址空间对外表现为一个 OPC UA Server消费侧Java客户端作为 OPC UA Client通过网络连接KepServerEX读取或订阅数据这里的关键认知是Java客户端面对的不是PLC而是KepServerEX暴露出来的OPC UA接口。KepServerEX把设备的方言翻译成了普通话OPC UA就是那门普通话。好处非常直接——项目里哪怕后来新增了一种协议的设备只要KepServerEX有对应驱动Java代码一行都不用改。1.1 理解OPC UA里的Server和Client不止是技术概念我用一个生活化的例子讲清楚OPC UA的通信模型。把OPC UA Server看成一家银行的金库金库里摆着无数个带编号的保险柜Node节点每个保险柜里放着客户的资产设备实时值。OPC UA Client是拿着钥匙的客户代理它不能直接闯进金库去翻保险柜只能站在柜台前Session会话提出请求——要么看一眼保险柜里的值Read要么跟柜员说这个柜子有变化就通知我Subscribe。KepServerEX就是这家银行它把车间那些PLC里的寄存器地址全部重新编号整理成规范的保险柜目录地址空间然后营业。Java客户端要做的事情就是以一个合法客户的身份找到自己关心的那几个保险柜号码NodeId告诉柜员这几个我有兴趣然后坐着等通知。这个模型我一开始也理解偏了以为订阅就是轮询用定时器每秒钟去Read一次。后来发现OPC UA的订阅机制本质上是由Server端主动推送变更通知Client只需要建立Subscription并登记关注的节点数据变化的推送由Server侧完成。下面会重点讲代码层面的实现但这个谁推谁的认知要先立住。1.2 KepServerEX在链路中的真正价值如果只是测试用一个开源的OPC UA模拟服务器就能跑通协议生产环境为什么还要引入KepServerEX我个人的体会是有三件事绕不开第一是协议适配。车间现场的PLC型号不会为你的Java程序改变通信方式但KepServerEX有几百种设备驱动常见品牌和协议基本全覆盖。第二是点位的工程化管理。KepServerEX里可以用通道、设备、标签三层结构组织数据和车间实际布局保持一致设备点位上千也能维护得井井有条。第三是数据稳定性和安全边界。KepServerEX本身有缓冲、日志、错误重连机制设备突然断线时它不会把异常直接怼到上层客户端而是用Bad状态标识点位Java端只需要处理状态变化就行。我见过一些团队没有用KepServerEX直接用Java写PLC私有协议项目刚开始觉得挺好等设备数量上来、协议种类一多每台设备的连接管理和数据解析都变成独立模块维护成本直接起飞。用KepServerEX中转本质上是把不断适配新协议这种脏活外包给专业工具。1.3 先明确场景边界避免选型过度这套方案也不是灵丹妙药。如果只是单台PLC的数据采集数据量不大也没有多系统共享数据的需求那直接用Java跑一个轻量Modbus协议包成本更低。如果项目要求采集链路必须穿透若干层网络或对时延有极其苛刻的要求那OPC UA本身是基于TCP的请求/订阅通信加上KepServerEX这一层中转端到端时延通常能做到百毫秒级但对硬实时控制类需求比如运动控制里的位置同步它并不是合适的技术路径。OPC UA更适合状态监控、生产统计、历史存储、报表分析这类介于慢速控制和日常管理之间的数据通道。我通常在技术选型时画一条线数据用途是给人看、给系统算还是给机器控。给人看给系统算走KepServerEX OPC UA这套链路非常顺手给机器控还是让PLC之间啃协议去别把常规IT技术塞进实时控制回路里。2. KepServerEX侧配置通道、标签、OPC UA端点设置很多搞Java的人习惯先写代码后配环境但在这个项目里顺序反了——你得先让KepServerEX把OPC UA端点开出来拿到能够连接的地址、端口、认证信息Java代码才有明确的目标。我建议在KepServerEX的配置界面花半天时间彻底摸熟后面少走很多弯路。2.1 核心配置清单从建通道到开启OPC UA服务登录KepServerEX的Administration界面默认是Windows机器上的桌面应用创建采集链路的顺序是固定的步骤操作位置要做什么常见误解1通道新建通道选择设备驱动如Simulator模拟器、Siemens TCP/IP等通道不是逻辑分组每个通道对应一个通信驱动实例2设备在通道下添加设备配置IP、端口、通讯参数设备地址格式依赖驱动类型需查驱动文档3标签在设备下添加标签映射寄存器地址/数据类型标签名会成为NodeId的一部分命名要有规则4OPC UA配置在项目属性里开启OPC UA服务设置端口、安全策略默认关闭必须手动开启第一次测试我强烈建议用KepServerEX自带的Simulator驱动它能模拟出一堆简单的整数、浮点、布尔标签不用连真PLC就能把Java端逻辑跑通。等Java订阅逻辑稳定了再切换真实设备驱动排查问题的时候就能区分是协议层问题还是应用层问题。2.2 OPC UA服务端启用细节端口、安全策略、匿名访问在KepServerEX界面左侧项目树里找到OPC UA配置节点里面有Server端的关键参数。我把测试环境和生产环境的配置经验分别说一下测试环境我会把安全策略临时设为None允许匿名访问端口用默认的49320不同版本可能不一样以配置界面实际显示为准。连接地址格式是opc.tcp://192.168.1.100:49320IP换成KepServerEX所在机器的实际地址。注意KepServerEX的OPC UA服务和Windows防火墙的相爱相杀——服务本身监听端口没问题但外部机器访问时防火墙入站规则必须放行这个TCP端口否则Java客户端能解析到端点但连接总是超时。生产环境我会开启Basic256Sha256安全策略创建用户账号不要用匿名。这样做的目的不只是防外部攻击更重要的是符合很多头部工厂的IT安全审计要求。用Milo做安全连接时需要额外处理应用证书的信任关系第4章会有一节专门展开。2.3 NodeId的来龙去脉KepServerEX标签在OPC UA空间里怎么组织这是新手最容易卡住的一环。KepServerEX默认命名空间索引是2一般情况是这样以实际获取为准它把通道、设备、标签映射成类似ns2;sChannel1.Device1.Tag1这样的字符串节点。这里面的规律一句话就能说清s后面的字符串就是把KepServerEX界面上从通道到标签的完整路径用点拼接起来。比如你在KepServerEX里建了通道MyChannel设备MyDevice标签MyTag那这个标签对应的NodeId大概率就是ns2;sMyChannel.MyDevice.MyTag。大小写敏感中间的设备名、通道名也必须和配置完全一致。我在第4章会讲到很多订阅不到数据的问题根源就是这里拼错了。这里有个实用技巧在KepServerEX的OPC UA配置界面可以直接浏览Micro Embedded或UA Expert这类工具看到的地址空间树核对NodeId是不是你拼的那个。我用过的UA Expert是个免费的OPC UA客户端工具能直接连KepServerEX看地址结构强烈建议在写Java代码前先用它看一眼真实的NodeId格式。2.4 开发期最好用的Java SDKEclipse Milo选型理由Java生态里能用的OPC UA SDK不多我最终选的是Eclipse Milo理由很直接它是开源的社区活跃实现了标准OPC UA协议栈不用被商业授权卡脖子。另一个常见选择是Prosys OPC UA SDK文档和商业支持更好但要评估license费用。Milo按模块划分客户端对应milo-client这个依赖。我这边用Maven引入方式如下dependency groupIdorg.eclipse.milo/groupId artifactIdmilo-client/artifactId version0.6.11/version /dependency版本号不用太纠结选一个稳定的发布版即可API在0.6.x系列里变化不大。如果网络环境拉不下来这个依赖想办法配一个Maven镜像仓库。引入之后涉及的核心类主要有这几个OpcUaClient客户端入口负责连接、会话、订阅管理OpcUaClientConfig连接配置承载端点URL、证书、认证信息Subscription订阅对象规定数据推送的节奏MonitoredItem监视项具体指向某个关心NodeId第3章的代码就是围绕这几个类展开的先有这个整体印象后面读代码不会迷路。3. Java客户端核心实现连接、订阅与反向写入的完整代码这一章是全文的技术核心。我会按真实开发顺序走一遍初始化客户端、建立连接、创建订阅、添加监视项、处理回调。最后补上一小段反向写入的代码因为推送数据到KepServerEX如果理解成Java端向KepServerEX写入数据其实也有实际应用场景。3.1 第一步创建OpcUaClient并完成连接握手先用Milo创建一个最小客户端。连接前需要准备Endpoint描述最简单的方式是让Milo根据URL自行发现端点import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; import org.eclipse.milo.opcua.stack.client.DiscoveryClient; // 引入其他需要用到的类 public class KepOpcUaClient { public static void main(String[] args) throws Exception { String endpointUrl opc.tcp://192.168.1.100:49320; // 方式一直接用URL创建客户端Milo内部会去发现端点 OpcUaClient client OpcUaClient.create(endpointUrl, endpoints - endpoints.stream() .filter(e - e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri())) .findFirst(), configBuilder - configBuilder.build()); client.connect().get(); System.out.println(连接成功会话已建立); // ... 后续订阅操作 // 结束时断开 client.disconnect().get(); } }这段代码里有一个关键筛选逻辑endpoints.stream()...filter...findFirst()。KepServerEX开启OPC UA服务后可能暴露多个端点分别对应不同的安全策略。测试阶段我们只想要SecurityPolicy.None的端点所以主动过滤出来。如果筛选条件留空或者选了带安全策略的端点又没配置证书握手会直接失败。生产环境想用Basic256Sha256加用户名密码认证筛选条件和配置就要换后面有一节专门说。3.2 订阅机制真正实现推送数据的核心姿势很多人以为OPC UA客户端是拉数据其实协议层面的典型模式是订阅。客户端创建一个Subscription然后往这个Subscription里添加MonitoredItemKepServerEX会按照配置的采样间隔检查点位变化变化发生后通过发布间隔把数据打包推给客户端。Java端要做的事就三件创建订阅、添加监视项、写回调。// 创建订阅发布间隔为1000ms var subscription client.getSubscriptionManager() .createSubscription(1000.0) .get(); // 准备需要监视的NodeId NodeId nodeId new NodeId(2, MyChannel.MyDevice.MyTag); // 创建监视项要求采样间隔500ms var monitoredItem subscription.createMonitoredItem( nodeId, MonitoringParameters.defaults());createSubscription(1000.0)里的参数是发布间隔publishing interval毫秒数它决定了KepServerEX最多多久推一次数据MonitoringParameters.defaults()里的采样间隔sampling interval决定了点位值多久被检查一次。这两个时间参数配合起来才是数据推送节奏的完整答案——采样间隔决定多久看一眼KepServerEX内部的缓存值发布间隔决定多久把变化批量送一次给客户端。初学者如果发现数据更新慢往往只调发布间隔忽略了采样间隔也要联动调整。3.3 写回调在数据变更通知里做什么不做什么添加监视项后需要给MonitoredItem挂一个数据变更监听器。Milo的API在0.6.x里通常这样写// 方式一事件监听方式推荐 subscription.addItemListener((item, value) - { System.out.println(节点 item.getNodeId() 的值为: value.getValue().getValue() 状态: value.getStatusCode()); }); // 方式二在创建监视项时传入监听器 var monitoredItem subscription.createMonitoredItem( nodeId, MonitoringParameters.defaults(), (item, value) - { // 这里处理收到的数据 });回调里拿到的value.getValue().getValue()就是KepServerEX推过来的实际值Java类型和KepServerEX标签的数据类型有关。比如标签类型是Word这里拿到的可能是Short或Integer是Float这里就是Float对象。再往上层推给MES系统时通常在这里把数据封装成统一DTO再交给后续的消息队列或HTTP接口。这里有一个我踩过很深刻的坑回调线程不适合做耗时操作。Milo回调默认跑在Netty的EventLoop线程上如果你在回调里直接写文件、调远程接口、操作数据库数据量大时会把事件循环堵住表现为订阅消息越来越慢甚至断连。正确的做法是回调只做轻量转发——塞进一个带缓冲的线程池或消息队列——由下游单独消费。3.4 反向写入Java把数据推给KepServerEX写回PLC标题里推送数据到KepServerEX如果指的是Java端主动写数据那Milo也支持写值对应的API是writeValue。// 想要写入的节点例如给某个模拟器的输入点位写值 NodeId writeNodeId new NodeId(2, MyChannel.MyDevice.WriteTag); // 写入的数据注意类型要和标签定义一致 DataValue dataValue DataValue.valueOnly(new Variant(123)); StatusCode statusCode client.writeValue(writeNodeId, dataValue).get(); System.out.println(写入结果: statusCode);写操作很直接但有几个现实问题一是KepServerEX的标签是否允许外部写入取决于驱动和设备本身的能力不是所有寄存器都能写二是写操作没有订阅那么常用需要明确业务场景比如远程下发配方参数、置位启动标志。如果只是上位系统要控制设备动作我一般建议大家先确认这套链路是否被现场自动化工程师认可因为在产线上写错一个值可能引起连锁反应。3.5 一个完整的可运行骨架把上面的片段拼成一个可用的小Demo方便照着改public class KepOpcUaDemo { public static void main(String[] args) { try { OpcUaClient client OpcUaClient.create( opc.tcp://192.168.1.100:49320, endpoints - endpoints.stream() .filter(e - e.getSecurityPolicyUri() .equals(SecurityPolicy.None.getUri())) .findFirst(), b - b.build()); client.connect().get(); // 订阅 Subscription subscription client.getSubscriptionManager() .createSubscription(1000.0) .get(); NodeId nodeId new NodeId(2, MyChannel.MyDevice.MyTag); subscription.createMonitoredItem(nodeId, MonitoringParameters.defaults(), (item, value) - { System.out.println(收到数据: value.getValue().getValue()); }); // 让主线程别退出保持订阅活动 Thread.sleep(60000); client.disconnect().get(); } catch (Exception e) { e.printStackTrace(); } } }跑通这个Demo后整个链路的验证就算完成了。如果你连KepServerEX都还没部署可以先找社区版的OPC UA模拟服务器替代测试Java代码几乎不用改动只有NodeId格式和地址空间结构有差异。4. 建连与订阅的实战排障我记录的KepServerEX连接问题清单这一章值得反复翻阅。与KepServerEX对接过程中我把遇到的每个异常都记了排查链路列在这里。每个问题我都尽量写清现象和根因方便对照。4.1 连接超时端点和防火墙的双重坑现象Java客户端执行connect().get()时抛出OpcUaException或超时异常KepServerEX日志无记录或显示连接被拒绝。排查步骤先确认能否ping通KepServerEX主机的IP。用telnet 主机IP 49320测试端口连通性连不上基本就是防火墙拦截或服务没启动。到KepServerEX配置界面看OPC UA服务是否处于Running状态很多版本默认是Stopped需要手动应用配置。Windows防火墙入站规则里放行49320/TCP别只关了Windows防火墙就完事——有些工厂网络里还有带ACL的交换机或上层防火墙。这个坑我当初耗时最久。因为KepServerEX和应用都跑在同一台电脑上本地连接正常远程就是超时结果只是Windows防火墙的独立入站规则没建。放行规则后客户端秒连。4.2 SecurityPolicy不匹配你能看到端点但握手就是失败现象连接阶段抛出BadSecurityModeRejected或BadCertificateInvalid之类的状态码。原因Java客户端筛选端点时用了SecurityPolicy.None但KepServerEX端强制开启了Basic256Sha256或者反过来客户端选了带安全策略的端点却没有提供可用的证书。解决把两端的安全策略调到一致。测试阶段我建议都在KepServerEX侧选None并允许匿名访问要上生产安全策略见后面认证升级小节。用SecurityPolicy.None时有个细节容易漏——Milo筛选端点还会看SecurityModeNone/Sign/SignAndEncryptSecurityPolicy.None通常对应SecurityMode.None筛选条件尽量两者都匹配。4.3 证书信任问题为什么总报BadCertificateUntrusted现象用Basic256Sha256连接时Milo日志提示BadCertificateUntrusted证书不受信任连接被拒绝。原理OPC UA双向认证机制里客户端和服务端都要向对端出示应用证书然后互相信任。Milo首次运行会在用户目录生成或加载应用证书KepServerEX默认不信任一个陌生客户端证书。解决思路找到Milo生成的应用证书位置一般在用户主目录下的/milo或类似路径下的DER/PFX文件。打开KepServerEX的OPC UA配置界面找到受信任客户端列表把Milo证书添加进去。同时在Java端配置信任KepServerEX的服务端证书这通常要把KepServerEX导出的证书导入到Java的信任存储。受信任列表更新后重启KepServerEX的OPC UA服务或重新应用配置。这块配置比较繁琐但对生产环境是必须的。我自己的经验是先在测试环境把证书互信关系彻底跑通形成文档生产环境照着做不然现场攒一堆信任问题很难定位。4.4 能连接但收不到数据先查NodeId和订阅权重现象连接正常、订阅也建成功但回调一直没有输出或者只有部分点位有数据。排查方向先在KepServerEX界面确认对应标签有没有实时值变化。Simulator模拟器会周期性变化真实PLC需要确认设备通信正常。用UA Expert连接KepServerEX在地址空间树里找到目标节点核对NodeId字符串。很多时候是s字符串里的通道/设备/标签名和配置对不上。注意KepServerEX标签所在的命名空间索引不一定是2以UA Expert实际显示的ns为准。检查监视项的采样间隔和订阅发布间隔是否过慢。设备变化很快但你设了60s的发布间隔看起来就像没推送。确认绑定的订阅对象没有被GC回收。这是Java新手很容易踩的坑——订阅对象创建后没有保持强引用被垃圾回收后监视项随之消失程序还不报错。4.5 数据推过来类型不对Variant类型转换异常现象回调抛ClassCastException比如把值直接(Float)强转实际却是Double类型。原因KepServerEX标签映射到OPC UA数据类型时可能发生提升或转换比如整型标签可能以Int64形式推送。对策回调里拿到Variant后先判断数据类型再做转换。Milo的Variant.getValue()返回Object可以读它的真实类名或调用instanceof判断。写一层数据转换工具类统一处理比在各处强转安全得多。5. 从Demo走向生产稳定性、重连、吞吐量的工程化改造Demo跑通了只是第一步往生产环境上放的时候又是另一批问题。工业采集链路有个特点要么不出问题一出问题就在凌晨两三点。所以这章讲的不是功能而是出事之后怎么办和如何尽量不出事。5.1 断线自动重连订阅链路的基础保障网络不可能永远稳定交换机重启、网线被老鼠咬断、KepServerEX服务例行维护都会让客户端连接断开。Java进程如果直接退出聊天后半夜的监控数据就空窗了。我在生产实现里做了三层防护监听连接状态Milo的OpcUaClient提供了连接监听接口断开时会回调可以在回调里做日志告警。定时健康检查如果事件回调没触发就用一个后台定时任务周期性地检查连接和订阅是否仍然有效。自动重连重建订阅发现连接异常后依次执行disconnect、清理旧订阅、重新connect、重新创建订阅和监视项。注意一定要重建订阅——重连后的Subscription对象已经是无效状态不重建就和第4章说的收不到数据一模一样。有人会用进程守护脚本只要Java进程活着就不管连接层面的事。但进程活着不代表订阅活着合理的设计应该是进程内自愈加上进程级守护双重保障。5.2 生产环境的认证升级从匿名到用户名密码加证书测试环境可以裸奔生产环境不建议。KepServerEX可以配置OPC UA用户账号Java端按如下方式配置OpcUaClientConfig config OpcUaClientConfig.builder() .setEndpoint(endpoint) .setIdentityProvider(new UsernameIdentityProvider(opcUser, opcPassword)) .setCertificate(certificate) .setKeyPair(keyPair) .build();其中UsernameIdentityProvider来自Milo的org.eclipse.milo.opcua.stack.client.security包。setCertificate和setKeyPair需要提前生成好客户端证书并且服务端已经信任该证书。这里的证书生成和信任导入可以看我第4章证书问题的排查记录。生产环境使用用户名密码的另一个好处是审计可追溯——KepServerEX的日志里能看到哪个用户建立了会话。5.3 订阅回调的消费模型改造别把EventLoop线程卡死前面提过一次回调线程问题这里展开讲工程化方案。工业现场数据频率高的点位可能几百毫秒推一次如果订阅几百个点位回调会被高频触发。在回调里直接做阻塞式IO基本等于自杀。我现在的标准做法是// 回调里只做一件事扔进队列 BlockingQueueMonitoredItemValue queue new LinkedBlockingQueue(10000); subscription.createMonitoredItem(nodeId, params, (item, value) - { queue.offer(new MonitoredItemValue(item.getNodeId(), value)); }); // 单独线程消费 ExecutorService consumer Executors.newSingleThreadExecutor(); consumer.submit(() - { while (true) { MonitoredItemValue val queue.take(); // 这里才做写库、推送MES、记录日志 handle(val); } });为什么单独消费线程就够了因为KepServerEX的发布节奏按照秒级、百毫秒级设计后端写库和推送完全来得及。如果确实遇到极高吞吐场景再改成消息队列做批量削峰先别急着加并发复杂度。5.4 数据质量与状态码处理不只是读值还要读状态设备数据里藏着不少没被留意的状态信息。OPC UA的DataValue里除了Value还有StatusCode和SourceTimestamp。实测中我发现很多点位会在设备断线、通信超时时返回一个Bad状态码但值可能还停留在最后一次正常读数——这时候如果直接拿值去统计分析数据分析结果就会悄悄出问题。所以生产代码里每条数据都应该带状态判断if (value.getStatusCode().isGood()) { // 值有效进入正常处理链路 } else { // 值无效记录异常状态触发告警或标记数据异常 }isGood()之外还有isBad()、isUncertain()等情况。我的习惯是所有进入数据库的数据都保留状态码字段宁可让数据分析端多做一层过滤也不能让坏数据佯装成正常值。5.5 一次性订阅多个点位批量添加与分组管理监控任务不会只盯一个标签可能一台设备几十个点位。逐个createMonitoredItem也行但更高效的做法是规划好订阅的结构把同一台设备、同一刷新需求的点位放同一个Subscription下采样间隔一致不同需求比如有的点位一秒要看一次有的五分钟采集一次放到不同订阅里管理。这样一个Subscription出现异常时只影响一组数据不至于全盘崩掉。KepServerEX里上千个标签不是一次性订阅完的我的经验是先订阅核心状态点位再按需动态增加。Milo支持运行时动态增删MonitoredItem所以完全可以根据业务需要做成自动发现、动态订阅的模型——比如从配置文件读点位列表启动时批量订阅。写在最后的经验和一条小技巧这套Java KepServerEX OPC UA的链路我先后在两个项目里落地过。回头看最大的心得是技术本身不算复杂真正决定成败的是对数据链路整体边界的理解——知道每一层负责什么、每一环可能在哪里出问题。KepServerEX解决协议适配和点位管理OPC UA解决通信标准化Java解决业务消费和系统对接三层各司其职系统才能稳定。最后分享一个小技巧。上线调试时我习惯先在KepServerEX自带的快速客户端诊断工具里看点位值变化确认数据源活跃之后再让Java连接。这样一旦订阅不到数据能直接确认问题出在Java端还是KepServerEX端。省掉来回猜的过程整个联调时间至少缩短三分之一。这套链条跑顺之后后续哪怕接入新设备也只是在KepServerEX上增加驱动和标签Java代码躺在服务器上不用动——这大概就是一开始选这个架构最大的回报。
返回列表