C#OPC(下)

安装 OPC UA SDK

通过 NuGet 包管理器,在 Visual Studio 中右键单击项目名称,选择 "管理 NuGet 程序包",在搜索框中输入 "OPCFoundation.NetStandard.Opc.Ua",找到对应的 OPC UA SDK 包后点击 "安装",将其集成到 C# 项目中。

它和OPC安装流程一样。

配置 OPC UA 客户端应用程序

  • 创建一个ApplicationConfiguration对象,用于配置 OPC UA 客户端的应用程序名称、应用程序 URI、产品 URI、安全配置等信息。例如:
cs 复制代码
ApplicationConfiguration config = new ApplicationConfiguration()
{
    ApplicationName = "OPC UA Client",
    ApplicationUri = "urn:localhost:OPC-UA-Client",
    ProductUri = "urn:OPC-UA-Client",
    SecurityConfiguration = new SecurityConfiguration
    {
        ApplicationCertificate = new CertificateIdentifier
        {
            StoreType = "Directory",
            StorePath = @"C:\OPC_UA_Client_Certificates",
            SubjectName = "OPC-UA-Client"
        }
    },
    TransportConfigurations = new TransportConfigurationCollection(),
    ClientConfiguration = new ClientConfiguration()
};
config.Validate(ApplicationType.Client);

连接到 OPC UA 服务器

  • 使用EndpointDescription类指定 OPC UA 服务器的端点地址,格式通常为 "opc.tcp:// 服务器 IP 地址:端口号"。例如:EndpointDescription endpointDescription = EndpointDescription.Create("opc.tcp://localhost:4840");
cs 复制代码
EndpointDescription endpointDescription = EndpointDescription.Create("opc.tcp://localhost:4840");
  • 创建EndpointConfigurationConfiguredEndpoint对象,用于配置和定义连接到服务器的端点。
cs 复制代码
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(config);
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
  • 使用Session.Create方法创建一个 OPC UA 会话,用于与服务器进行通信。
cs 复制代码
Session session = Session.Create(config, endpoint, false, "OPC-UA-Client", 60000, new UserIdentity(new AnonymousIdentityToken()), null).Result;

读取设备数据

  • 确定要读取的设备数据对应的 OPC UA 节点 ID,可以通过设备的文档或在 OPC UA 服务器的地址空间中查找获得。例如,假设要读取一个名为 "ns=2;s=Demo.Static.Scalar.Double" 的节点的值:
cs 复制代码
NodeId nodeId = new NodeId("ns=2;s=Demo.Static.Scalar.Double");
DataValue dataValue = session.ReadValue(nodeId);
Console.WriteLine($"Node Value: {dataValue.Value}");

写入设备数据

  • 确定要写入的设备数据对应的 OPC UA 节点 ID 和要写入的值。例如,要向一个名为 "ns=2;s=Demo.Static.Scalar.Int" 的节点写入整数值 100:
cs 复制代码
NodeId nodeId = new NodeId("ns=2;s=Demo.Static.Scalar.Int");
DataValue dataValue = new DataValue(100);
session.WriteValue(nodeId, dataValue);

订阅数据变更和处理事件

  • 使用MonitoredItem类创建一个监控项,指定要监控的节点 ID 和监控模式等。例如:
cs 复制代码
NodeId nodeId = new NodeId("ns=2;s=Demo.Static.Scalar.Double");
MonitoredItem monitoredItem = new MonitoredItem(session.DefaultSubscription,
    1000,
    nodeId,
    MonitoringMode.Reporting,
    null);
monitoredItem.Notification += OnDataChange;
session.DefaultSubscription.AddItem(monitoredItem);
session.DefaultSubscription.ApplyChanges();
  • 在事件处理方法中处理数据变更通知。例如:
cs 复制代码
private static void OnDataChange(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args)
{
    DataValue dataValue = args.NotificationValue;
    Console.WriteLine($"Data changed: {dataValue.Value}");
}

断开与 OPC UA 服务器的连接

当不再需要与 OPC UA 服务器通信时,调用session.Close方法关闭会话,释放资源。例如:

cs 复制代码
session.Close();

OPC-UA协议通信

cs 复制代码
using Opc.Ua;
using Opc.Ua.Client;
using System;
using System.Threading.Tasks;

class OpcUaClient
{
    private static ApplicationConfiguration config;
    private static Session session;

    static async Task Main()
    {
        // 配置应用程序
        config = new ApplicationConfiguration()
        {
            ApplicationName = "OPC UA Client",
            ApplicationUri = "urn:localhost:OPC-UA-Client",
            ProductUri = "urn:OPC-UA-Client",
            SecurityConfiguration = new SecurityConfiguration
            {
                ApplicationCertificate = new CertificateIdentifier
                {
                    StoreType = "Directory",
                    StorePath = @"C:\OPC_UA_Client_Certificates",
                    SubjectName = "OPC-UA-Client"
                }
            },
            TransportConfigurations = new TransportConfigurationCollection(),
            ClientConfiguration = new ClientConfiguration()
        };
        config.Validate(ApplicationType.Client);

        // 尝试连接到服务器
        try
        {
            await ConnectToServer("opc.tcp://localhost:4840");
            Console.WriteLine("Connected to OPC UA Server.");

            // 读取数据
            await ReadData();

            // 写入数据
            await WriteData();

            // 订阅数据
            await SubscribeData();

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();

            // 关闭会话
            await DisconnectFromServer();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }

    // 连接到服务器
    static async Task ConnectToServer(string endpointUrl)
    {
        EndpointDescription endpointDescription = EndpointDescription.Create(endpointUrl);
        EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(config);
        ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
        session = await Session.Create(config, endpoint, false, "OPC-UA-Client", 60000, new UserIdentity(new AnonymousIdentityToken()), null);
    }

    // 读取数据
    static async Task ReadData()
    {
        NodeId nodeId = new NodeId("ns=2;s=Demo.Static.Scalar.Double");
        DataValue dataValue = await session.ReadValueAsync(nodeId);
        Console.WriteLine($"Read value from node {nodeId}: {dataValue.Value}");
    }

    // 写入数据
    static async Task WriteData()
    {
        NodeId nodeId = new NodeId("ns=2;s=Demo.Static.Scalar.Int");
        DataValue dataValue = new DataValue(100);
        await session.WriteValueAsync(nodeId, dataValue);
        Console.WriteLine($"Wrote value to node {nodeId}");
    }

    // 订阅数据
    static async Task SubscribeData()
    {
        NodeId nodeId = new NodeId("ns=2;s=Demo.Static.Scalar.Double");
        MonitoredItem monitoredItem = new MonitoredItem(session.DefaultSubscription,
            1000,
            nodeId,
            MonitoringMode.Reporting,
            null);
        monitoredItem.Notification += OnDataChange;
        session.DefaultSubscription.AddItem(monitoredItem);
        await session.DefaultSubscription.ApplyChangesAsync();
        Console.WriteLine($"Subscribed to node {nodeId}");
    }

    // 处理数据变更事件
    private static void OnDataChange(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args)
    {
        DataValue dataValue = args.NotificationValue;
        Console.WriteLine($"Data changed: {dataValue.Value}");
    }

    // 断开连接
    static async Task DisconnectFromServer()
    {
        if (session!= null)
        {
            await session.CloseAsync();
            Console.WriteLine("Disconnected from OPC UA Server.");
        }
    }
}

OPC-UA实例解释:

  • 配置应用程序:

    • ApplicationConfiguration对象用于配置客户端的各种信息,包括应用程序名称、URI、安全配置等。

    • SecurityConfiguration部分指定了证书存储的类型、路径和主题名称,确保安全通信。

    • config.Validate(ApplicationType.Client)用于验证客户端配置是否正确。

  • 连接到服务器:

    • ConnectToServer方法根据提供的端点 URL 创建端点描述和配置,然后使用Session.Create创建会话。

    • 端点 URL 格式为 opc.tcp://服务器IP地址:端口号,使用 AnonymousIdentityToken 作为用户身份令牌。

  • 读取数据:

    • ReadData方法使用NodeId指定要读取的节点,然后使用session.ReadValueAsync方法异步读取该节点的值。

    • NodeId包含节点的命名空间索引和标识符,通过它可以唯一确定一个节点。

  • 写入数据:

    • WriteData方法使用NodeId指定要写入的节点,并创建一个包含要写入值的DataValue对象。

    • 然后使用session.WriteValueAsync方法将该值写入节点。

  • 订阅数据:

    • SubscribeData方法使用MonitoredItem类创建一个监控项,指定要监控的节点和监控模式。

    • monitoredItem.Notification += OnDataChange注册一个事件处理程序,当数据变化时触发OnDataChange方法。

    • session.DefaultSubscription.ApplyChangesAsync()将订阅更改应用到会话。

  • 数据变更事件处理:

    • OnDataChange方法接收MonitoredItemNotificationEventArgs,从中提取数据值并输出。
  • 断开连接:

    • DisconnectFromServer方法使用session.CloseAsync关闭会话。

使用说明:

  • 确保在运行代码前,已经在 C:\OPC_UA_Client_Certificates 目录下配置了相应的证书(或者根据实际情况修改证书存储路径)。

  • 代码中假定 OPC UA 服务器的端点为 opc.tcp://localhost:4840,请根据实际服务器信息修改。

  • 代码中的节点 ns=2;s=Demo.Static.Scalar.Doublens=2;s=Demo.Static.Scalar.Int 仅为示例,需根据实际服务器中的节点进行修改。

这个示例展示了如何使用 C# 和 OPC UA 进行基本的连接、读取、写入和订阅操作。

OPC-UA协议通信注意事项

安全方面

  • 证书管理:OPC UA 通常依赖于证书进行身份验证和加密。确保正确配置客户端和服务器的证书,包括证书的生成、存储和加载。如果证书配置错误或不匹配,可能导致连接失败或安全漏洞,如在客户端配置中指定正确的证书存储路径和证书主题名称。

  • 用户身份验证:根据服务器的安全策略,可能需要提供有效的用户身份信息进行登录。除了匿名访问外,还可能涉及用户名 / 密码、X.509 证书等多种身份验证方式,要确保正确处理身份验证过程,以获取相应的访问权限。

  • 网络安全:由于 OPC UA 通信通常在网络环境中进行,要确保网络的安全性,如使用防火墙限制对 OPC UA 端口的访问,只允许授权的 IP 地址连接到 OPC UA 服务器,防止网络攻击和未经授权的访问。

连接与配置

  • 端点配置:正确配置 OPC UA 服务器的端点地址,包括协议(如 opc.tcp://)、服务器 IP 地址和端口号等。如果端点配置错误,将无法建立连接,可通过网络配置工具或咨询服务器管理员获取准确的端点信息。

  • 会话管理:合理地创建、使用和关闭会话。在使用完会话后及时关闭,以释放资源并确保与服务器的连接状态正确维护,避免出现资源浪费或连接异常的情况。

  • 性能调优:根据实际应用场景,可能需要调整 OPC UA 客户端的性能相关配置,如设置合适的会话超时时间、操作超时时间、订阅采样间隔等,以平衡通信效率和系统资源消耗。

数据处理

  • 数据类型映射:OPC UA 中的数据类型与 C# 中的数据类型可能不完全一致,需要进行正确的映射。在读取和写入数据时,确保将 OPC UA 数据类型正确转换为 C# 中的相应数据类型,反之亦然,以避免数据错误或丢失。

  • 数据一致性:在进行批量数据读写或订阅多个节点时,要注意数据的一致性和同步性,确保在处理数据时不会出现数据冲突或不一致的情况,特别是在多线程或异步操作的环境中。

  • 错误处理:在数据读写和订阅过程中,可能会出现各种错误,如节点不存在、权限不足、网络故障等。要全面地捕获和处理这些错误,提供清晰的错误提示和相应的处理机制,以提高系统的稳定性和可靠性。

兼容性与版本

  • OPC UA 规范版本:确保客户端和服务器都遵循相同版本的 OPC UA 规范,不同版本之间可能存在功能和数据结构的差异,导致通信问题或功能不兼容,必要时进行协议版本的适配和升级。

  • 库版本兼容性:使用的 OPC UA 客户端库要与项目的其他依赖库和目标运行环境兼容,避免出现版本冲突或不兼容的情况,及时更新库版本以获取最新的功能和修复已知的问题。

内存管理

  • 资源释放:在使用 OPC UA 相关对象,如会话、订阅、监控项等时,要及时释放它们占用的内存和系统资源,特别是在长时间运行的应用程序中,防止内存泄漏导致系统性能下降甚至崩溃。

  • 大型数据处理:当处理大量的 OPC UA 数据时,要注意内存的使用情况,避免一次性加载过多数据导致内存溢出,可以采用分页、缓存等策略优化内存使用。

相关推荐
胜天半月子9 分钟前
Python | 学习type()方法动态创建类
开发语言·python·学习
Zer0_on1 小时前
C++string类
开发语言·c++
Tomorrow'sThinker1 小时前
25年1月更新。Windows 上搭建 Python 开发环境:Python + PyCharm 安装全攻略(文中有安装包不用官网下载)
开发语言·python·pycharm
禁默1 小时前
深入浅出:Java 抽象类与接口
java·开发语言
白宇横流学长2 小时前
基于Java的银行排号系统的设计与实现【源码+文档+部署讲解】
java·开发语言·数据库
勉灬之2 小时前
封装上传组件,提供各种校验、显示预览、排序等功能
开发语言·前端·javascript
西猫雷婶5 小时前
python学opencv|读取图像(二十三)使用cv2.putText()绘制文字
开发语言·python·opencv
我要学编程(ಥ_ಥ)5 小时前
速通前端篇——JavaScript
开发语言·前端·javascript
HEU_firejef6 小时前
设计模式——工厂模式
java·开发语言·设计模式
云计算DevOps-韩老师6 小时前
【网络云SRE运维开发】2024第52周-每日【2024/12/31】小测-计算机网络参考模型和通信协议的理论和实操考题
开发语言·网络·计算机网络·云计算·运维开发