opc ua로 시작하기 때문에, 나는 opc ua의 통신 계층에서 일어나는 일을 알고 싶었습니다.Opc-UA 통신 프로토콜, 클라이언트가 사용 가능한 서버 노드를 어떻게 이해합니까?
주소 공간에 3 개의 노드가있는 매우 간단한 서버 구현 예를 들어 보겠습니다. 이 노드는 opc-UA 클라이언트가 읽고 쓸 수있는 데이터를 제공합니다.
open62541과 함께 제공되는 코드의 일부를 읽으면서 TCP를 통해 통신이 이루어지는 것을 알게되었습니다. 서버가 클라이언트가 연결할 수있는 소켓을 시작하고 클라이언트가 노드에서 다양한 작업을 수행 할 수 있음을 의미합니다.
제 질문은 클라이언트가 사용 가능한 서버 노드를 어떻게 알 수 있습니까? 주소 공간을 탐색하지만 사용 가능한 노드를 찾기 위해 정확히 어디에서 찾아 볼 수 있습니까? opc-UA는 사용 가능한 노드를 클라이언트에 표시하기 위해 어떤 노출 메커니즘을 사용합니까? 서버가 일부 XML 파일이나 다른 곳에서 사용 가능한 정보 인 &을 쓸 수 있습니까? 따라서 클라이언트가 연결할 때 주소 공간 구조를 이해하기 위해 파일의 내용을 읽으려고합니까? open62541
#include <stdio.h>
#include <open62541.h>
#include <signal.h>
static void
addVariable(UA_Server *server) {
/* Define the attribute of the myInteger variable node */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = 43;
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;
/* Add the variable node to the information model */
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_NULL, attr, NULL, NULL);
}
static void
addThirdVariable(UA_Server *server) {
/* Define the attribute of the myInteger variable node */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_String myInteger = UA_STRING("My name is variable 3"); // variable name
UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_STRING]);
attr.description = UA_LOCALIZEDTEXT("en-US", "the answer");
attr.displayName = UA_LOCALIZEDTEXT("en-US", "the answer");
attr.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* Add the variable node to the information model */
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "third.variable");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "third varaible");
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_NULL, attr, NULL, NULL);
}
void addSecondVariable(UA_Server * server) {
//variable attributes
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_String machine_name = UA_STRING("My name is a machine"); // variable name
UA_Variant_setScalar(&attr.value, &machine_name, &UA_TYPES[UA_TYPES_STRING]);
attr.description = UA_LOCALIZEDTEXT("en-US", "machine name");
attr.displayName = UA_LOCALIZEDTEXT("en-US", "machine name");
attr.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
//setting access level not important
//add the variable to the information model
UA_NodeId myStringNodeID = UA_NODEID_STRING(1, "the.machine");
UA_QualifiedName myStringName = UA_QUALIFIEDNAME(1, "the machine");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(server, myStringNodeID, parentNodeId,
parentReferenceNodeId, myStringName,
UA_NODEID_NULL, attr, NULL, NULL);
}
UA_Boolean running = true;
static void stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
int main(void) {
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_ServerConfig *config = UA_ServerConfig_new_default();
UA_Server *server = UA_Server_new(config);
addVariable(server);
addSecondVariable(server);
addThirdVariable(server);
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
UA_ServerConfig_delete(config);
return (int)retval;
}
OPC는 UA 클라이언트 서비스 FindServers 및 GetEndpoints을 사용하여야한다 . 먼저 OPC UA에 대한 정보를 얻으시기 바랍니다. OPC UA에 대한 도서 목록은 다음과 같습니다. https://opcfoundation.org/resources/books/ –