open62541 (http://open62541.org) 是用 C 语言编写的 OPC UA(OPC 统一架构/IEC 62541)的开源实现。该库可与所有主要编译器一起使用,并提供必要的工具来实现专用 OPC UA 客户端和服务器,或将基于 OPC UA 的通信集成到现有应用程序中。 open62541 库是独立于平台的:所有特定于平台的功能都是通过可交换插件实现的,以便轻松移植到不同(嵌入式)目标。
open62541 根据 Mozilla 公共许可证 v2.0 (MPLv2) 获得许可。这使得 open62541 库可以与任何专有软件组合和分发。在复制和分发时,只有对 open62541 库本身的更改需要根据 MPLv2 获得许可。插件以及服务器和客户端示例均属于公共领域(CC0 许可证)。它们可以在任何许可下重复使用,并且不必发布更改。
该库以标准源代码和二进制形式提供。此外,单文件源代码分发将整个库合并为单个 .c 和 .h 文件,可以轻松添加到现有项目中。示例服务器和客户端实现可以在 /examples 目录或本页的下方找到。
open62541 实现了 OPC UA SDK,支持服务器、客户端和 PubSub(发布-订阅)通信。有关完整详细信息,请参阅功能概述。
open62541 根据 MPLv2 获得许可。也就是说,对 MPLv2 下的文件进行的更改属于同一开源许可证。但是,即使生成静态二进制文件,该库也可以与来自单独文件的私有开发相结合,而许可证不会影响私有文件。有关详细信息,请参阅完整的许可文档。
Fraunhofer IOSB雇用了多名 open62541 开发人员并提供商业支持。 open62541.org 上列出了 open62541 生态系统中的其他服务提供商。
使用 open62541 v1.0 构建的示例服务器 (server_ctt) 符合 OPC 基金会的“微型嵌入式设备服务器”配置文件,支持 OPC UA 客户端/服务器通信、订阅、方法调用和安全性(加密),安全策略为“Basic128Rsa15” '、'Basic256' 和 'Basic256Sha256' 以及方面 '方法服务器' 和 '节点 管理'。有关更多详细信息,请参阅 https://open62541.org/certified-sdk。
PubSub (UADP) 在 open62541 中实现。但由于缺乏官方测试用例和测试工具,该功能目前无法获得认证(2019 年 9 月)。
在开发过程中,定期应用OPC基金会的一致性测试工具(CTT)。 CTT 配置和结果可在 https://github.com/open62541/open62541-ctt 上跟踪。目前在 CTT 中定期测试的 OPC UA 配置文件有:
请参阅 open62541 功能页面,深入了解对构成 OPC UA 配置文件的一致性单元的支持。
有关 OPC UA 的一般介绍和 open62541 文档,请访问 http://open62541.org。该库的过去版本可以在 https://github.com/open62541/open62541/releases 下载。
整个 open62541 社区处理 Github 和邮件列表上的公共支持请求。如需个人讨论和支持,请使用以下渠道:
我们希望建立一个开放、热情的社区。请考虑我们的行为准则。
open62541的构建环境是通过CMake生成的。有关详细信息,请参阅构建文档。为了简化与现有软件项目的集成,可以将 open62541 源代码压缩(合并)为单个文件分发,即一对open62541.c/.h
文件。单文件发行版中包含的功能取决于当前的 CMake 配置。
源代码结构如下:
/include
):公共 API 向使用 open62541 的应用程序公开。插件实现的标头位于/plugins/include
中。/src
):除了 C99 标准头之外,核心库没有任何依赖项。/arch
):架构支持是通过EventLoop
插件实现的。这将特定于体系结构的代码(例如使用 POSIX API)保留在核心库之外。提供了不同(嵌入式)架构的端口。/plugins
):插件接口允许与不同的后端系统和库集成。例如关于加密原语、信息模型的存储等等。提供了默认实现。/deps
):一些附加库通过 git 子模块使用或已内化到deps/
文件夹中。有关第三方库及其各自许可证的更多信息可以在 deps/README.md 中找到在大多数系统上,一个简单的 open62541 仅需要 C 标准库。根据构建配置,open62541 依赖于其他库,例如用于加密的 mbedTLS 或 OpenSSL。
作为一个开源项目,我们鼓励新的贡献者帮助改进 open62541。文件 CONTRIBUTING.md 汇总了我们期望的代码贡献的良好实践。以下是新贡献者的良好起点:
对于最终将成为 open62541 库一部分的定制开发,请让核心维护者之一了解情况。
我们强调代码质量。以下质量指标经过持续检查,并确保在正式发布之前保持有效:
该项目建立了处理漏洞的流程。有关详细信息以及如何负责任地向维护人员披露调查结果,请参阅 SECURITY.md。
代码示例可以在 /examples 目录中找到。要构建示例,我们建议安装上一节中提到的 open62541。使用 GCC 编译器,只需运行gcc -std=c99
(在 Windows 下,您可能需要添加针对ws2_32
套接字库的额外链接)。
#include
int main ( int argc , char * * argv )
{
/* Create a server listening on port 4840 (default) */
UA_Server * server = UA_Server_new ();
/* Add a variable node to the server */
/* 1) Define the variable attributes */
UA_VariableAttributes attr = UA_VariableAttributes_default ;
attr . displayName = UA_LOCALIZEDTEXT ( "en-US" , "the answer" );
UA_Int32 myInteger = 42 ;
UA_Variant_setScalar ( & attr . value , & myInteger , & UA_TYPES [ UA_TYPES_INT32 ]);
/* 2) Define where the node shall be added with which browsename */
UA_NodeId newNodeId = UA_NODEID_STRING ( 1 , "the.answer" );
UA_NodeId parentNodeId = UA_NS0ID ( OBJECTSFOLDER );
UA_NodeId parentReferenceNodeId = UA_NS0ID ( ORGANIZES );
UA_NodeId variableType = UA_NODEID_NULL ; /* take the default variable type */
UA_QualifiedName browseName = UA_QUALIFIEDNAME ( 1 , "the answer" );
/* 3) Add the node */
UA_Server_addVariableNode ( server , newNodeId , parentNodeId ,
parentReferenceNodeId , browseName ,
variableType , attr , NULL , NULL );
/* Run the server (until ctrl-c interrupt) */
UA_StatusCode status = UA_Server_runUntilInterrupt ( server );
/* Clean up */
UA_Server_delete ( server );
return status == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE ;
}
#include
#include
#include
int main ( int argc , char * argv [])
{
/* Create a client and connect */
UA_Client * client = UA_Client_new ();
UA_ClientConfig_setDefault ( UA_Client_getConfig ( client ));
UA_StatusCode status = UA_Client_connect ( client , "opc.tcp://localhost:4840" );
if ( status != UA_STATUSCODE_GOOD ) {
UA_Client_delete ( client );
return status ;
}
/* Read the value attribute of the node. UA_Client_readValueAttribute is a
* wrapper for the raw read service available as UA_Client_Service_read. */
UA_Variant value ; /* Variants can hold scalar values and arrays of any type */
UA_Variant_init ( & value );
status = UA_Client_readValueAttribute ( client , UA_NODEID_STRING ( 1 , "the.answer" ), & value );
if ( status == UA_STATUSCODE_GOOD &&
UA_Variant_hasScalarType ( & value , & UA_TYPES [ UA_TYPES_INT32 ])) {
printf ( "the value is: %in" , * ( UA_Int32 * ) value . data );
}
/* Clean up */
UA_Variant_clear ( & value );
UA_Client_delete ( client ); /* Disconnects the client internally */
return status == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE ;
}