若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/148868209

长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

Qt开发专栏:三方库开发技术

上一篇:《Qt+OPC开发笔记(二):OPC客户端介绍与读取和写入bool类型Demo》
下一篇:敬请期待…


前言

  本篇介绍opc客户端订阅消息,实现一个opc事件的订阅,当订阅的数据在服务器发生变化是,客户端能立即得到更新。


Demo

  请添加图片描述


OPC客户端

  OPC 客户端是一种利用OPC(OLE for Process Control)协议与 OPC 服务器进行通信的软件应用程序。

功能特点

  • 数据访问:提供一套简单易用的 API,使开发人员能轻松地创建、读取、更新和删除OPC服务器上的数据项,可从传感器、PLC、DCS 系统、过程分析仪等各种数据源获取实时数据。
  • 事件订阅(当前使用):支持实时数据变化订阅,当服务器端的数据发生变化时,客户端能够立即获取到更新,以便及时响应和处理数据变化。
  • 连接管理:负责建立和管理与 OPC 服务器的连接,包括连接的建立、监控连接状态以及在发生异常时进行重连或断开。
  • 数据展示与处理:允许用户创建和管理数据视图,通常以表格或图形的方式展示实时数据流,还能对采集到的数据进行分析、存储、归档等处理,为决策提供支持。

数据访问方式

  OPC 协议支持多种数据访问方式,以满足不同的应用场景需求:

  • 同步访问:客户端发送请求后会一直等待,直到服务器返回响应。这种方式适用于对实时性要求较高的场景,但如果服务器响应时间较长,可能会导致客户端程序阻塞。
  • 异步访问:客户端发送请求后不会等待服务器响应,而是继续执行后续操作。当服务器处理完请求后,会通过回调函数通知客户端。这种方式可以提高客户端程序的效率,避免阻塞。
  • 订阅访问(当前使用):客户端可以订阅特定的数据项,当这些数据项的值发生变化时,服务器会主动将更新后的数据推送给客户端。这种方式适用于需要实时监控数据变化的场景。

订阅服务器某个消息

步骤一:连接服务器

  在这里插入图片描述

步骤二:创建订阅

  在这里插入图片描述

  在这里插入图片描述

步骤三:创建监听项

  在这里插入图片描述

步骤四:处理回调函数

  这里是通过subId与监控id对应来确定是哪一个变量变化。
  在这里插入图片描述

步骤五:Qt兼容使用定时器定时调用

  在这里插入图片描述


Demo关键源码

创建订阅和监控项

bool OpcClientManager::createSubscriptionResponse()
{/*OPC UA中的订阅是异步的。也就是说,客户端向服务器发送多个PublishRequest。服务器返回带有通知的PublishResponses。但只有在生成通知时。客户端不会等待响应,而是继续正常操作。请注意订阅和受监视项目之间的区别。订阅用于报告通知。MonitoredItems用于生成通知。每个MonitoredItem只附加到一个订阅。订阅可以包含许多受监视的项目。客户端在后台自动处理PublishResponses(带回调),并在传输中保留足够的PublishRequests。ublishResponses可以在同步服务调用期间或在“UA_Client_run_iterate”中接收*/// 步骤一:创建一个默认的订阅请求对象(有订阅再开放)_subscriptionRequest = UA_CreateSubscriptionRequest_default();_subscriptionRequest.requestedPublishingInterval = 1000; // 设置发布间隔为1000毫秒,即每秒发布一次数据_subscriptionRequest.requestedLifetimeCount = 300;       // 设置生命周期计数为300,即服务器在300个发布周期后会终止该订阅_subscriptionRequest.requestedMaxKeepAliveCount = 10;    // 设置最大保持活动计数为10,即服务器在10个发布周期内没有数据变化时,仍会发送空的通知以保持连接活跃_subscriptionRequest.maxNotificationsPerPublish = 0;     // 设置每个发布周期的最大通知数为0,表示不限制通知数量_subscriptionRequest.publishingEnabled = true;           // 启用发布功能,允许服务器主动推送数据_subscriptionRequest.priority = 0;                       // 设置订阅的优先级为0,数值越高优先级越高// 步骤二:设置订阅回复,设置状态改变通知回调和删除订阅回调_subscriptionResponse = UA_Client_Subscriptions_create(_pUAClient,_subscriptionRequest,NULL,OpcClientManager::statusChangeNotificationCallback,OpcClientManager::deleteSubscriptionCallback);if(_subscriptionResponse.responseHeader.serviceResult != UA_STATUSCODE_GOOD){LOG << QString("Failed to UA_Client_Subscriptions_create, error code: 0x%1").arg(UA_StatusCode_name(_subscriptionResponse.responseHeader.serviceResult));return false;}LOG << "Succeed to UA_Client_Subscriptions_create, id:" << _subscriptionResponse.subscriptionId;startTimer(100);return true;
}bool OpcClientManager::createMonitoredItemRequest(int ns, int i)
{// 前置:有一个订阅实例// 步骤三:创建监控项请求,需要传入监控的节点LOG << ns << i;UA_NodeId nodeId = UA_NODEID_NUMERIC(ns, i);UA_MonitoredItemCreateRequest monitoredItemCreateRequest = UA_MonitoredItemCreateRequest_default(nodeId);monitoredItemCreateRequest.requestedParameters.samplingInterval = 100;  // 采样间隔(单位:毫秒),指定服务器多久读取一次被监控变量的实际值。monitoredItemCreateRequest.requestedParameters.discardOldest = true;    // 当监控项的队列(Queue)已满时,是否丢弃最早的数据。monitoredItemCreateRequest.requestedParameters.queueSize = 10;          // 服务器为该监控项保留的历史值队列大小。queueSize = 10 表示服务器最多保存10个未发送给客户端的值// 添加监控项到订阅UA_MonitoredItemCreateResult monResult = UA_Client_MonitoredItems_createDataChange(_pUAClient,_subscriptionResponse.subscriptionId,UA_TIMESTAMPSTORETURN_BOTH,monitoredItemCreateRequest,NULL,OpcClientManager::dataChangeNotificationCallback,NULL);if(monResult.statusCode != UA_STATUSCODE_GOOD){LOG << "监控项创建失败 error:" << QString(UA_StatusCode_name(monResult.statusCode));return false;}else{LOG << "成功监控节点 MonId: " << monResult.monitoredItemId;return true;}}

回调函数

void OpcClientManager::statusChangeNotificationCallback(UA_Client *client, UA_UInt32 subId, void *subContext, UA_StatusChangeNotification *notification)
{LOG << __FUNCTION__ << client << subId;
}void OpcClientManager::deleteSubscriptionCallback(UA_Client *client, UA_UInt32 subId, void *subContext)
{LOG << __FUNCTION__ << client << subId;
}void OpcClientManager::dataChangeNotificationCallback(UA_Client *client, UA_UInt32 subId, void *subContext, UA_UInt32 monId, void *monContext, UA_DataValue *value)
{LOG << __FUNCTION__ << client << subId;LOG << "数据变化通知 - 监控项ID: " << monId;if(value->hasValue && value->value.type){UA_Variant *var = &value->value;if(var->type == &UA_TYPES[UA_TYPES_BOOLEAN]){LOG << *static_cast<bool *>(var->data);}else{LOG << "other types";}}
}

定时器处理

void OpcClientManager::timerEvent(QTimerEvent *event)
{if(_pUAClient){UA_Client_run_iterate(_pUAClient, 100);}
}

工程模板v1.2.0

  在这里插入图片描述


入坑

入坑一:订阅变量后未通知

问题

  订阅变量后未通知
  在这里插入图片描述

尝试

  检查代码没有发现任何问题,考虑是否有其他问题。
  更换第三方单文件全代码订阅后,变化 也无通知:
  在这里插入图片描述

  使用uaexpert测试,订阅看起来是成了:
  在这里插入图片描述

  修改成5秒,发现就是5秒了,所以这里订阅是成功了。
  继续考虑代码问题了,再次查看,发现可能是打印缓存的问题,Qt输出printf需要设置stdout为0:
  在这里插入图片描述

  那么这个代码是没问题的。
  回到封装的代码,对比检查,发下关键性代码:
  在这里插入图片描述

  在这里插入图片描述

  所以open ua这个代码,收到订阅通知需要跑这个循环才可以收到。
在OPC UA通信中,客户端需要持续运行并处理服务器推送的通知,而UA_Client_run_iterate函数正是用于实现这一点的关键机制。
  然后查看了其他一边监听一边写入的代码,跟想象中一样,间隔写入(PS:就是单片机的单路径一样)
  在这里插入图片描述

解决

  本意是用Qt的消息循环替代:
  在这里插入图片描述
  这个靠Qt循环的不是那么准确,还需要完善这个流程,有可能处理会有2次一同处理。


上一篇:《Qt+OPC开发笔记(二):OPC客户端介绍与读取和写入bool类型Demo》
下一篇:敬请期待…


本文章博客地址:https://hpzwl.blog.csdn.net/article/details/148868209

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/86086.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/86086.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/86086.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式开发学习日志Day8(ARM体系架构——按键、蜂鸣器及中断)

一、蜂鸣器学习 代码实现&#xff1a; 二、BSP工程管理及Makefile 1、BSP工程管理 利用BSP工程管理&#xff0c;使文档显示不杂乱&#xff1b; 将这些文件分为4类&#xff0c;并保存到4个不同的文件夹里。 首先在新的工程文件夹里创建一个之后我们编写的类似led驱动&#xff0…

Linux部署Sonic前后端(详细版)(腾讯云)

系统用的是Ubuntu 22.04 LTS 1、安装Docker sudo apt update sudo apt install -y docker.io docker-compose sudo systemctl start docker sudo systemctl enable docker# 如果不想每次用 sudo&#xff0c;可以加权限 sudo usermod -aG docker $USER 2、安装 docker-compose…

腾讯云CBS:企业级云存储的性能与可靠性重构

摘要 根据Forrester 2025年网络分析与可见性&#xff08;NAV&#xff09;报告&#xff0c;东西向流量安全与加密威胁检测成为企业核心痛点&#xff08;误报率降低需求↑40%&#xff09;。腾讯云CBS作为底层存储支柱&#xff0c;通过三副本跨可用区冗余架构与毫秒级故障切换能力…

ubuntu 22.04 更换阿里源 (wsl2 参照)

步骤 1: 备份当前源列表 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 步骤 2: 编辑源列表文件 sudo nano /etc/apt/sources.list 步骤 3: 添加阿里云镜像源 ubuntu 阿里源地址可以在这查看 ubuntu镜像_ubuntu下载地址_ubuntu安装教程-阿里巴巴开源镜像站 …

idea中push拒绝,merge,rebase的区别

在 IntelliJ IDEA 中进行 Git 操作时&#xff0c;Push 拒绝&#xff08;Push Rejected&#xff09;、Merge 和 Rebase 是常见的冲突解决方式。它们有不同的适用场景和影响&#xff0c;下面详细说明它们的区别&#xff0c;并附上流程图帮助理解。 1. Push 拒绝&#xff08;Push …

轻松实现PDF局部擦除的技术级解决方案

在处理PDF文档时&#xff0c;我们常常会遇到这样的场景&#xff1a;想要删除某段文字、擦除一张图片&#xff0c;或者对页面内容进行局部调整。但很多编辑工具要么操作繁琐&#xff0c;要么功能受限&#xff0c;甚至还需要付费解锁核心功能。 这是一款轻便又实用的PDF编辑工具…

css color 十六进制颜色透明度

css color 十六进制颜色透明度 例&#xff1a;#FFFFFF ~~ #FFFFFF1A(10% ) 0% 为 FF10% 为 1A20% 为 3330% 为 4D40% 为 6650% 为 8060% 为 9970% 为 B380% 为 CC90% 为 E6100% 为 00

Git简介和常用命令

Git简介 Git是一款版本管理软件&#xff0c;可以在任何时间点保存文件&#xff0c;也能够恢复到以前任意时间点保存的文档&#xff0c;Git作用简单举例来说就是&#xff0c;写论文&#xff0c;有很多个版本&#xff0c;将原来的论文保存起来&#xff0c;新建一个副本&#xff…

Kafka 性能调优指南

文章目录 概述操作系统层面调优文件系统优化内存管理磁盘 I/O 优化 JVM 调优堆内存设置GC 收集器选择常见 GC 问题 Broker 端调优版本兼容性关键参数配置日志段大小调优设置原则推荐配置调优考虑因素监控命令 应用层调优客户端复用资源管理多线程消费模式 性能指标调优吞吐量优…

佰力博科技与您探讨低温真空探针台如何保养

低温真空探针台是一种用于在低温或真空环境下进行电学性能测试的精密仪器&#xff0c;其保养和维护对于确保设备的稳定运行和延长使用寿命至关重要。 一、日常清洁与检查 1、使用后应立即清洁探针台&#xff0c;尤其是探针、接口和连接器&#xff0c;避免灰尘和杂质影响精度。…

MySQL:深入总结锁机制

写在前面 在 MySQL 数据库中&#xff0c;锁机制是保障并发控制和数据一致性的关键。合理运用锁机制&#xff0c;能有效避免数据竞争&#xff0c;提升数据库性能。接下来&#xff0c;我们就深入了解 MySQL 中的各类锁。 博主总结&#xff08;注&#xff1a;针对总结的详解补充在…

AI+OT安全,让威胁情报实现主动防御

当前&#xff0c;网络犯罪组织的运作模式正日趋“企业化”&#xff0c;给全球网络安全带来了严峻挑战。企业以及各类组织机构有必要采用威胁情报驱动的防御体系&#xff08;Threat-Informed Defense, TID&#xff09;&#xff0c;将安全运营模式从被动响应彻底转向基于威胁情报…

深度剖析:UDS上下行分离隧道如何绕过主流防火墙?

&#x1f525; 深度剖析&#xff1a;UDS上下行分离隧道如何绕过主流防火墙&#xff1f; &#x1f4ca; 系统架构图 #mermaid-svg-lv5FKIvBMKPeTFuW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-lv5FKIvBMKPeTFuW …

Vue 使用vue-cli

Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - 使用Vue-cli 笔记 目录 使用vue-cli 创建项目 配置文件 启动项目 入口文件 Index.html Main.js Eslint修复 第一种 第二种 第三种 更换为淘宝源 查看当前配置 配置淘宝源 验证配置 总结 使用vue-cli 创建项目…

Sentinel实现原理

Sentinel 是阿里巴巴开源的分布式系统流量控制组件&#xff0c;主要用于服务保护&#xff0c;涵盖流量控制、熔断降级、系统负载保护等功能。 以下是 Sentinel 的实现原理&#xff0c;使用中文简要说明&#xff1a; 1. 总体架构 Sentinel 采用 轻量级 设计&#xff0c;分为 核…

DeepSeek生成HTML5生命天数计算器

DeepSeek生成HTML5生命天数计算器 让DeepSeek生成一个生命天数计算器 提示词prompt 帮我做一个我活了多少天的网页 用户输入出生日期即可显示我活了多少天 页面ui要好看点&#xff0c;加上显示官方统计 人一生平均可以活多少天 自动计算剩余天数。帮我按照上述需求再次生成一个…

如何使typora图片不居中留白?

如何使typora图片不居中留白&#xff1f; 驻波使用typora记笔记的时候&#xff0c;好几次插入图片太大选择缩小都会发现图片仍然滞留在中间&#xff0c;居中显示&#xff0c;但我本人觉得并不好看&#xff0c;所以我决定改一下&#xff0c;于是有了这篇博客 检查看原理 软件内…

高精度频率基石:超低相噪恒温晶振的全场景应用解决方案

在科技高速发展的今天&#xff0c;频率源作为电子系统的 “心脏”&#xff0c;其稳定性与可靠性直接决定着通信、导航、测量等关键领域的性能上限。深度洞察行业需求&#xff0c;重磅推出SYN3627L 型 100MHz 恒温晶振&#xff08;OCXO&#xff09;。这款集高稳定性、低相位噪声…

【android bluetooth 协议分析 01】【HCI 层介绍 27】【LeReadRemoteFeatures命令介绍】

深入理解 LE Read Remote Features 命令与事件响应 在蓝牙低功耗&#xff08;BLE&#xff09;通信中&#xff0c;设备特性&#xff08;LE Features&#xff09;协商是连接过程中的一个关键环节。本文将详细介绍 HCI 层的命令 LE_Read_Remote_Features 及其对应的事件响应 LE_R…

企业架构设计中的CBAM方法深度解析:成本效益驱动的架构决策艺术

目录 CBAM方法概述与核心价值 CBAM核心流程与实施步骤 前期准备与场景确定 成本效益建模与分析 风险调整与决策制定 实施技巧与挑战克服 CBAM实战案例与应用场景 案例一&#xff1a;电商平台促销系统架构选型 案例二&#xff1a;制造业ERP系统云迁移决策 案例三&…