文章目錄
- 簡介
- 目標
- 閱讀基礎
- 快速閱讀
- 環境說明
- 相關軟體
- 創建Server+Client的Qt工程Opcua_Server_Client
- 創建普通Qt工程
- 添加opcua62541庫到Qt工程
- 添加opcua代碼
- 添加opcua檔案
- 添加客戶端執行緒
- 添加服務器執行緒
- 主選單視窗
- 創建單Server的Qt工程Opcua_Single_Server
- 創建普通Qt工程
- 添加opcua62541庫到Qt工程
- 添加opcua代碼
- 添加opcua檔案
- 添加服務器執行緒
- 主選單視窗
- 變數監測
- UaExper客戶端監測Opcua_Single_Server服務端變數
- Opcua_Server_Client客戶端監測Opcua_Single_Server服務端變數
- UaExper客戶端監測Opcua_Server_Client服務端變數
- 資料流向
- 最新文章
簡介
在實際工程中,有的Server既充當Server也充當Client,

還可能會出現多個OPC UA Server構成的OPC UA網路,
假如有幾個設備用來采集資料,這些設備上都運行著OPC UA Server,不斷采集資料并更新,此時需要一個總的Server來收集這些設備采集的資料,最后用戶作為Client可以從這個總的Server上拿到這些資料,
那么這個總的Server對于設備來說是Client,對于用戶來說則是Server,OPC UA檔案上稱這個總的Server為Combined OPC UA Server and Client,

目標
使用Qt5.12建立另一個單服務器的工程A作為資料源,同時建立包括opcua服務端與opcua客戶端的一個工程B,同時然后使用B工程中的客戶端讀取A工程的服務器變數,更新到自己內部的同名變數里,再用Uaexpert讀取前A/B工程的同名變數值,A工程相當于資料源服務器,B工程相當于一個Combined Server,Uaexpert相當于客戶端,

閱讀基礎
- 了解Qt編程,
- 了解QtCreator的使用,
- 了解openua協議,open62541,
快速閱讀
如果比較熟悉Qt的使用,跳過基礎工程搭建,
環境說明
-
作業系統:Windows-10-64bit
-
Qt版本:Qt5.12.6+QtCreator4.10
-
Open62541:V1.2
相關軟體
UaExpoert,是一個功能齊全的 OPCUA 客戶端,能夠提供多個 OPCUA 組態檔和功能,
創建Server+Client的Qt工程Opcua_Server_Client
搭建連接工程,
創建普通Qt工程
創建視窗工程,

選擇工程存放的位置,下一步,

下一步–》下一步–》下一步,

下一步–》完成,

添加opcua62541庫到Qt工程
在Qt工程目錄下創建檔案夾opcua62541,把前面編譯的opcua62541.h,opcua62541.c檔案復制進來如下,

通過pri檔案的方式添加opcua62541.h,opcua62541.c到Qt工程,
在open62541檔案夾中新建opcua62541.pri檔案,
右鍵工程名—》Add New,

命名,選擇檔案夾,就是前面的open62541檔案夾,

下一步–》完成,

右鍵open62541.pri檔案–》remove–》Ok,通過在.pri檔案中添加代碼的方式添加opcua62541.h,opcua62541.c到Qt工程,

添加opcua62541.h,opcua62541.c到Qt工程,

添加成功,使用這種方式添加隨時可以通過注釋include(./open62541/open62541.pri)從工程中去掉open62541庫,

在.pro檔案中添加兩行代碼然后編譯,
LIBS += -lpthread libwsock32 libws2_32
QMAKE_CFLAGS += -std=c99
編譯成功,

添加opcua代碼
添加opcua檔案
參考上面添加pri檔案夾的方法,在Qt檔案夾內添加一個空檔案夾opcua,然后新建txt檔案,將檔案名改為opcua,后綴名改為.pri,
在.pro檔案中添加include(./opcua/opcua.pri),

新建

命名檔案,選擇存放位置,

下一步–》完成,

使用同樣的方法添加opcua_server.cpp、opcua_client.cpp、opcua_client.cpp,

添加客戶端執行緒
opcua_client.h
#ifndef OPCUA_CLIENT_H
#define OPCUA_CLIENT_H
#include <QThread>
#include <QDebug>
#include <QMutex>
#include <QWaitCondition>
extern "C"{
#include "../open62541/open62541.h"
}
extern QMutex mutex;//互斥鎖
extern QWaitCondition newdataAvailable;//通知
extern UA_Variant value;//變數可以保存任何型別的標量值和陣列
/**
* @brief Opcua客戶端執行緒
*
*/
class Opcua_Client : public QObject
{
Q_OBJECT
QThread m_thread;
public:
explicit Opcua_Client(QObject *parent = 0);
~Opcua_Client();
protected slots:
void tmain();// 執行緒入口函式
signals:
void VariableValue(UA_Variant value);//變數節點的屬性
void testSingnal(int test);
public://執行緒管理
void start();
bool isRunning();
void terminate();
void exit(int c);
void wait();
void StopClientThread(); //結束執行緒回圈
public://客戶端和遠程服務器之間的互動
/*客戶端管理*/
static void stopHandler(int sign);
void CreatOpcuaClient();//創建客戶端
UA_StatusCode ConnectToSever();//連接端
void DeleteOpcuaClient();//把客戶內部連接斷開
/*資料互動*/
void Client_readValueAttribute();//讀取變數節點的value屬性
void Client_writeValueAttribute();//對server里的變數節點value屬性寫入一個新值
void Client_clearVariant();//value屬性
void addVariable(UA_Server *server);//添加變數到服務器
void ClientReadServerValue();//讀服務端變數值
void ClientWriteServerValue();//寫服務端變數值
public://客戶端和本地服務器之間的資料傳遞
void ClientReadValue();//讀取從服務端獲得的變數值
public:
static UA_Boolean running;
UA_NodeId nodeId;
UA_Client *client;
UA_StatusCode retval;
/*客戶端和遠程服務器之間的互動*/
/*對執行緒的管理*/
bool m_stop = false; //停止執行緒
bool m_read_value = true;//讀取服務器變數
bool m_write_value = true;//寫入服務器變數
QMutex m_mutex;//互斥量
UA_Server *m_server;
/*客戶端和本地服務器之間的資料傳遞*/
UA_Variant value_to_lserver;//傳遞給本地server的值
};
#endif // OPCUA_CLIENT_H
opcua_client.cpp
#include "opcua_client.h"
#include "opcua_server.h"
UA_Boolean Opcua_Client::running = true;
void Opcua_Client::stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
QMutex mutex;//互斥鎖
QWaitCondition newdataAvailable;//通知
UA_Variant value;//變數可以保存任何型別的標量值和陣列
//stopHandler捕獲程式,在作業系統嘗試關閉時接收信號(中斷)
Opcua_Client::Opcua_Client(QObject *parent):
QObject(parent)
{
moveToThread(&m_thread);
connect(&m_thread, SIGNAL(started()), this, SLOT(tmain()));
nodeId= UA_NODEID_STRING(1,"the.answer");
client = nullptr;
retval = 0;
/*初始化value為0*/
UA_Int32 data = 0;
UA_Variant_init(&value);
UA_Variant_setScalar(&value, &data, &UA_TYPES[UA_TYPES_INT32]);
}
Opcua_Client::~Opcua_Client()
{
nodeId= UA_NODEID_STRING(1,"the.answer");
client = nullptr;
retval = 0;
m_thread.wait();// 同步設計
}
void Opcua_Client::tmain()
{
/* 創建客戶端接受連接 */
CreatOpcuaClient();
/* 創建客戶端接受連接 */
ConnectToSever();
while(!m_stop)//回圈主體
{
mutex.lock();
/* 讀取節點的 value 屬性*/
Client_readValueAttribute();
mutex.unlock();
newdataAvailable.wakeAll();//喚醒所有執行緒,有新資料了
m_thread.sleep(3);
}
m_thread.quit();
}
void Opcua_Client::start()
{
m_thread.start();// m_thread執行緒開啟,定義的tmain函式被呼叫(run函式也被呼叫,開啟事件回圈)
}
bool Opcua_Client::isRunning()
{
return m_thread.isRunning();
}
void Opcua_Client::terminate()
{
m_thread.terminate();
}
void Opcua_Client::exit(int c)
{
m_thread.exit(c);
}
void Opcua_Client::wait()
{
m_thread.wait();
}
void Opcua_Client::CreatOpcuaClient()
{
client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
}
void Opcua_Client::DeleteOpcuaClient()
{
/*把客戶內部連接斷開*/
UA_Client_delete(client);
qDebug()<<EXIT_SUCCESS;
}
UA_StatusCode Opcua_Client::ConnectToSever()
{
retval = UA_Client_connect(client, "opc.tcp://192.168.5.120:4840");
if(retval != UA_STATUSCODE_GOOD) {
UA_Client_delete(client);
qDebug()<<(int)retval<<"----connect fail----->";
return (int)retval;
}
}
void Opcua_Client::Client_readValueAttribute()
{
/* 讀取節點的 value 屬性,Ua_client_readvalueattribute 是作為ua_client_service_read 提供的原始讀取服務的包裝器, */
UA_Variant_init(&value);
/* 讀取Server變數節點值 */
// 變數的NodeId是string型別
nodeId = UA_NODEID_STRING(1,"the.answer");
if(retval == UA_STATUSCODE_GOOD)
{
//使用UA_Client_readValueAttribute()去讀取變數值
retval = UA_Client_readValueAttribute(client,nodeId,&value);
// 變數的資料型別是UA_Int32,第二個是判斷UA_Variant里是否有UA_Int32型別的資料
if(retval == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&value,&UA_TYPES[UA_TYPES_INT32]))
{
UA_Int32 variableValue = *(UA_Int32 *)value.data;
UA_LOG_INFO(UA_Log_Stdout,UA_LOGCATEGORY_USERLAND,"Variable Value From Single Server is:%d\n",variableValue);
}
}
}
void Opcua_Client::Client_writeValueAttribute()
{
/* 對server里的變數寫入一個新值 */
nodeId = UA_NODEID_STRING(1, "the.answer");
UA_Int32 change = 100;
UA_Variant newValue;
UA_Variant_init(&newValue);
UA_Variant_setScalar(&newValue, &change, &UA_TYPES[UA_TYPES_INT32]);
retval = UA_Client_writeValueAttribute(client, nodeId,&newValue);
}
void Opcua_Client::Client_clearVariant()
{
/* 清理value */
UA_Variant_clear(&value);
}
void Opcua_Client::addVariable(UA_Server *server)
{
/* 定義myInteger變數節點的屬性 */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = 42;
UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* 將該變數節點添加到資訊模型中 */
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1,"the.answer");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1,"the.answer");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(server,myIntegerNodeId,parentNodeId,
parentReferenceNodeId,myIntegerName,
UA_NODEID_NUMERIC(0,UA_NS0ID_BASEDATAVARIABLETYPE),
attr,NULL,NULL);
}
void Opcua_Client::StopClientThread()
{//停止執行緒
m_stop=true;
}
void Opcua_Client::ClientReadServerValue()
{//讀服務端變數值
m_read_value=false;
}
void Opcua_Client::ClientWriteServerValue()
{//寫服務端變數值
m_write_value=false;
}
void Opcua_Client::ClientReadValue()
{
}
添加服務器執行緒
opcua_server.h
#ifndef OPCUA_SERVER_H
#define OPCUA_SERVER_H
#include <QThread>
#include <QDebug>
#include <QMutex>
extern "C"{
#include "../open62541/open62541.h"
}
class Opcua_Server : public QObject
{
Q_OBJECT
QThread m_thread;
public:
explicit Opcua_Server(QObject *parent = nullptr);
~Opcua_Server() override;
protected slots:
void tmain();// 執行緒入口函式
public://執行緒管理
void start();
bool isRunning();
void terminate();
void exit(int c);
void wait();
void StopServerThread(); //結束執行緒
public://本地服務端管理
static void stopHandler(int sign);
void CreatOpcuaSever();
void DeleteOpcuaSever();
void RunOpcuaSever();
void addVariable(UA_Server *server);//添加變數到服務器
void setServerPort(int port);
void Server_readValueAttribute();
public:
static UA_Boolean running;
UA_Server *server;
UA_StatusCode retval;
/*對執行緒的管理*/
bool m_stop = false; //停止執行緒
bool m_add_variable = true;//添加變數節點
QMutex m_mutex;
};
#endif // OPCUA_SERVER_H
opcua_server.cpp
#include "Opcua_client.h"
#include "opcua_server.h"
UA_Boolean Opcua_Server::running = true;
//stopHandler捕獲程式,在作業系統嘗試關閉時接收信號(中斷)
void Opcua_Server::stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
Opcua_Server::Opcua_Server(QObject *parent):
QObject(parent)
{
moveToThread(&m_thread);
connect(&m_thread, SIGNAL(started()), this, SLOT(tmain()));
server = nullptr;
retval = 0;
m_thread.wait();// 同步設計
}
Opcua_Server::~Opcua_Server()
{
server = nullptr;
retval = 0;
}
void Opcua_Server::tmain()
{
/*設定服務器埠*/
setServerPort(4444);
/*添加變數到服務器*/
addVariable(this->server);
while(!m_stop)//回圈主體
{
/*將本地客戶端從遠程服務端讀取的到的資料寫入本地服務端*/
mutex.lock();
newdataAvailable.wait(&mutex);
UA_Int32 newvariableValue = *(UA_Int32 *)value.data;
UA_LOG_INFO(UA_Log_Stdout,UA_LOGCATEGORY_USERLAND,"local server value from local client is:%d\n",newvariableValue);
UA_NodeId nodeId = UA_NODEID_STRING(1, "the.answer");
UA_Variant_setScalar(&value, &newvariableValue, &UA_TYPES[UA_TYPES_INT32]);
UA_Server_writeValue(server, nodeId, value);
mutex.unlock();
m_thread.sleep(3);
}
m_thread.quit();
}
void Opcua_Server::start()
{
m_thread.start();// m_thread執行緒開啟,定義的tmain函式被呼叫(run函式也被呼叫,開啟事件回圈)
}
bool Opcua_Server::isRunning()
{
return m_thread.isRunning();
}
void Opcua_Server::terminate()
{
m_thread.terminate();
}
void Opcua_Server::exit(int c)
{
m_thread.exit(c);
}
void Opcua_Server::wait()
{
m_thread.wait();
}
void Opcua_Server::CreatOpcuaSever()
{
//創建服務器
server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
}
void Opcua_Server::DeleteOpcuaSever()
{
//洗掉服務器
UA_Server_delete(server);
retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
void Opcua_Server::RunOpcuaSever()
{
//運行服務器
retval = UA_Server_run(server, &running);
}
void Opcua_Server::addVariable(UA_Server *server)
{
/* 定義myInteger變數節點的屬性 */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = 42;
UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* 將該變數節點添加到資訊模型中 */
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1,"the.answer");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1,"the.answer");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(server,myIntegerNodeId,parentNodeId,
parentReferenceNodeId,myIntegerName,
UA_NODEID_NUMERIC(0,UA_NS0ID_BASEDATAVARIABLETYPE),
attr,NULL,NULL);
}
void Opcua_Server::StopServerThread()
{//停止執行緒
m_stop=true;
}
void Opcua_Server::setServerPort(int port)
{
UA_ServerConfig_setMinimal(UA_Server_getConfig(server), port, nullptr);
}
主選單視窗
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
extern "C"{
#include "open62541/open62541.h"
}
#include "opcua/opcua_client.h"
#include "opcua/opcua_server.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
void closeEvent(QCloseEvent *event);
private:
Ui::MainWindow *ui;
public:
Opcua_Client* m_thread_client;
Opcua_Server* m_thread_server;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
//全域變數
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*創建客戶端執行緒*/
m_thread_client = new Opcua_Client;
m_thread_client->start();//啟動客戶端執行緒
/*創建服務端端執行緒*/
//服務器在后面
m_thread_server = new Opcua_Server;
/*創建服務器*/
m_thread_server->CreatOpcuaSever();
/*服務器啟動執行緒*/
m_thread_server->start();
/*運行服務器*/
m_thread_server->RunOpcuaSever();
}
MainWindow::~MainWindow()
{
delete ui;
}
創建單Server的Qt工程Opcua_Single_Server
創建普通Qt工程
創建視窗普通Qt工程Opcua_Single_Server,參考上文,

添加opcua62541庫到Qt工程
參考上文,
添加opcua代碼
添加opcua檔案
參考上文,
添加服務器執行緒
opcua_server.h
#ifndef OPCUA_SERVER_H
#define OPCUA_SERVER_H
#include <QThread>
#include <QDebug>
#include <QMutex>
extern "C"{
#include "../open62541/open62541.h"
}
class Opcua_Server : public QObject
{
Q_OBJECT
QThread m_thread;
public:
explicit Opcua_Server(QObject *parent = 0);
~Opcua_Server() override;
protected slots:
void tmain();// 執行緒入口函式
public:
void start();
bool isRunning();
void terminate();
void exit(int c);
void wait();
public:
static void stopHandler(int sign);
void CreatOpcuaSever();
void DeleteOpcuaSever();
void RunOpcuaSever();
void addVariable(UA_Server *server);//添加變數到服務器
/*執行緒管理函式*/
void StopServerThread(); //結束執行緒
void setServerPort(int port);
public:
static UA_Boolean running;
UA_Server *server;
UA_StatusCode retval;
/*對執行緒的管理*/
bool m_stop = false; //停止執行緒
bool m_add_variable = true;//添加變數節點
};
#endif // OPCUA_SERVER_H
opcua_server.cpp
#include "opcua_server.h"
UA_Boolean Opcua_Server::running = true;
//stopHandler捕獲程式,在作業系統嘗試關閉時接收信號(中斷)
void Opcua_Server::stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
Opcua_Server::Opcua_Server(QObject *parent):
QObject(parent)
{
moveToThread(&m_thread);
connect(&m_thread, SIGNAL(started()), this, SLOT(tmain()));
server = nullptr;
retval = 0;
}
Opcua_Server::~Opcua_Server()
{
server = nullptr;
retval = 0;
m_thread.wait();// 同步設計
}
void Opcua_Server::tmain()
{
/*設定服務器埠*/
setServerPort(5555);
/*添加變數到服務器*/
addVariable(this->server);
UA_NodeId nodeId = UA_NODEID_STRING(1, "the.answer");
UA_Int32 data = 0;
UA_Variant value;
UA_Variant_init(&value);
while(!m_stop)//回圈主體
{
UA_Variant_setScalar(&value, &data, &UA_TYPES[UA_TYPES_INT32]);
UA_Server_writeValue(server, nodeId, value);
m_thread.sleep(3);
++data;
}
m_thread.quit();
}
void Opcua_Server::start()
{
m_thread.start();// m_thread執行緒開啟,定義的tmain函式被呼叫(run函式也被呼叫,開啟事件回圈)
}
bool Opcua_Server::isRunning()
{
return m_thread.isRunning();
}
void Opcua_Server::terminate()
{
m_thread.terminate();
}
void Opcua_Server::exit(int c)
{
m_thread.exit(c);
}
void Opcua_Server::wait()
{
m_thread.wait();
}
void Opcua_Server::CreatOpcuaSever()
{
//創建服務器
server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
}
void Opcua_Server::DeleteOpcuaSever()
{
//洗掉服務器
UA_Server_delete(server);
retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
void Opcua_Server::RunOpcuaSever()
{
//運行服務器
retval = UA_Server_run(server, &running);
}
void Opcua_Server::addVariable(UA_Server *server)
{
/* 定義myInteger變數節點的屬性 */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = 42;
UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* 將該變數節點添加到資訊模型中 */
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1,"the.answer");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1,"the.answer");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(server,myIntegerNodeId,parentNodeId,
parentReferenceNodeId,myIntegerName,
UA_NODEID_NUMERIC(0,UA_NS0ID_BASEDATAVARIABLETYPE),
attr,NULL,NULL);
}
void Opcua_Server::StopServerThread()
{//停止執行緒
m_stop=true;
}
void Opcua_Server::setServerPort(int port)
{
UA_ServerConfig_setMinimal(UA_Server_getConfig(server), port, nullptr);
}
主選單視窗
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
extern "C"{
#include "open62541/open62541.h"
}
#include "opcua/opcua_server.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
void closeEvent(QCloseEvent *event);
private:
Ui::MainWindow *ui;
private slots:
/*服務端*/
void on_btnStartServer_clicked();
void on_btnEndServer_clicked();
void on_btnClearSever_clicked();
public:
Opcua_Server* m_thread_server;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//啟動服務端執行緒 按鈕
qDebug() << "main() tid = " << QThread::currentThreadId();
m_thread_server = new Opcua_Server;
/*創建服務器*/
m_thread_server->CreatOpcuaSever();
/*服務器啟動執行緒*/
m_thread_server->start();
/*運行服務器*/
m_thread_server->RunOpcuaSever();
}
MainWindow::~MainWindow()
{
delete ui;
}
變數監測
UaExper客戶端監測Opcua_Single_Server服務端變數
UaExper連接Qt的單服務端Opcua_Single_Server,Opcua_Single_Server的變數屬性從0開始每3秒加1,客戶端中的變數值每3秒加1說明成功監測變數屬性值,
參考文章:【3】Opcua通信客戶端UaExpert和服務器KepServer的簡單使用

Opcua_Server_Client客戶端監測Opcua_Single_Server服務端變數
Opcua_Server_Client的客戶端執行緒讀取Opcua_Single_Server中的服務器變數屬性,并將其寫入本工程的服務端中,Opcua_Server_Client客戶端中讀到的Opcua_Single_Server同名變數值每3秒加1說明成功監測變數屬性值,Opcua_Server_Client服務端中讀到的Opcua_Single_Server同名變數值每3秒加1說明成功寫入變數屬性值,

UaExper客戶端監測Opcua_Server_Client服務端變數

資料流向
最終的資料流向如下圖,

最新文章
最新文章:【5】opcua62541實作兩個Server互動
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/289385.html
標籤:其他
