OPC Foundation SDK订阅功能使用及回调函数添加问题咨询
问题根因
你当前的代码仅完成了服务端侧订阅、监控项的资源创建,缺少两个核心逻辑:1. 客户端侧的通知回调处理器绑定 2. 发布请求(PublishRequest)的轮询触发逻辑,OPC UA协议规定订阅的通知数据由客户端主动发送PublishRequest拉取,没有这步自然无法触发回调。
具体解决步骤
1. 补全订阅创建的必要参数
你当前的CreateSubscriptionRequest没有显式开启发布开关,先补全配置:
CreateSubscriptionRequest req = new CreateSubscriptionRequest(); req.setRequestedPublishingInterval(250D); // 新增开启发布、最大保留通知数等配置 req.setRequestedMaxKeepAliveCount(UnsignedInteger.valueOf(10)); req.setRequestedLifetimeCount(UnsignedInteger.valueOf(100)); req.setPublishingEnabled(true); // 必须显式开启发布
2. 绑定通知回调监听器
给你获取的sessionChannel绑定通知处理监听器,回调逻辑写在监听器里:
sessionChannel.setNotificationListener(new NotificationListener() { @Override public void onNotificationData(UnsignedInteger subscriptionId, List<MonitoredItemNotification> notifications) { // 匹配对应订阅ID后处理数据 if (subscriptionId.equals(subid)) { for (MonitoredItemNotification notification : notifications) { // 拿到监控项的数值变化 DataValue value = notification.getValue(); System.out.println("收到数值更新:" + value.getValue().getValue()); // 你的业务逻辑写在这里 } } } @Override public void onStatusChangeNotification(UnsignedInteger subscriptionId, StatusChangeNotification statusChange) { // 订阅状态变化的回调处理 System.out.println("订阅状态变化:" + statusChange.getStatus()); } });
3. 启动PublishRequest轮询线程
需要单独开一个守护线程循环发送PublishRequest,拉取服务端的通知数据,触发上面的回调:
new Thread(() -> { while (!sessionChannel.isClosed()) { try { PublishRequest publishRequest = new PublishRequest(); // 简单实现可先传空的确认序列 publishRequest.setSubscriptionAcknowledgements(new SubscriptionAcknowledgement[0]); sessionChannel.Publish(publishRequest); // 间隔略小于发布间隔即可,避免请求过于频繁 Thread.sleep(100); } catch (InterruptedException e) { break; } catch (ServiceException e) { // 处理服务异常,可根据业务需要加重试逻辑 e.printStackTrace(); } } }, "opc-ua-publish-thread").start();
4. 补充监控项创建校验逻辑
可以加一步判断监控项是否创建成功,避免配置错误导致无回调触发:
CreateMonitoredItemsResponse crp = sessionChannel.CreateMonitoredItems(null,subid,TimestampsToReturn.Both,mrs); // 新增校验逻辑 MonitoredItemCreateResult result = crp.getResults()[0]; if (result.getStatusCode().isBad()) { System.out.println("监控项创建失败:" + result.getStatusCode()); }
内容的提问来源于stack exchange,提问作者kolio
相关产品推荐
相关产品推荐

