You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用.NET平台C#连接OPC UA服务器并实现读写操作?

基于OPC UA Foundation库的Windows Forms客户端实现方案

核心问题修正

你的代码存在几个关键错误:

  • 错误的Session实例化方式:Foundation库中Session不能直接new,必须通过Session.Create方法创建并初始化连接。
  • 缺失节点订阅逻辑:没有实现trigger节点的数值变化监听,这是业务逻辑的核心触发点。
  • NodeId格式不规范:直接用字符串创建NodeId时,需确认服务器上节点的命名空间索引,否则无法正确定位节点。
  • 连接流程不完整:缺少客户端配置、安全策略设置等必要步骤,导致连接失败。

完整实现代码

以下是符合需求的完整代码,包含服务器连接、节点变化监听、读写节点的完整逻辑:

using System;
using System.Windows.Forms;
using Opc.Ua;
using Opc.Ua.Client;

namespace OPCUAExample
{
    public partial class MainForm : Form
    {
        private Session _opcSession;
        private Subscription _opcSubscription;
        // 替换为服务器对应节点的命名空间索引(默认通常为1,可通过UA客户端工具查看)
        private const ushort NamespaceIndex = 1;

        public MainForm()
        {
            InitializeComponent();
        }

        private async void MainForm_Load(object sender, EventArgs e)
        {
            try
            {
                // 1. 初始化客户端配置
                var clientConfig = new ApplicationConfiguration
                {
                    ApplicationName = "OPC UA WinForms Client",
                    ApplicationType = ApplicationType.Client,
                    SecurityConfiguration = new SecurityConfiguration
                    {
                        AutoAcceptUntrustedCertificates = true // 测试环境允许自签名证书,生产环境需配置合法证书
                    },
                    TransportConfigurations = new TransportConfigurationCollection(),
                    TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
                    ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 }
                };
                await clientConfig.Validate(ApplicationType.Client);

                // 2. 获取服务器端点
                var endpointUrl = "opc.tcp://localhost:4840";
                var endpoint = CoreClientUtils.SelectEndpoint(endpointUrl, useSecurity: false);

                // 3. 创建并打开Session
                _opcSession = await Session.Create(
                    clientConfig,
                    new ConfiguredEndpoint(null, endpoint, EndpointConfiguration.Create(clientConfig)),
                    false,
                    "WinForms OPC UA Session",
                    60000,
                    null,
                    null);

                MessageBox.Show("连接OPC UA服务器成功", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);

                // 4. 创建订阅,监听trigger节点变化
                SetupSubscription();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"连接失败:{ex.Message}\n{ex.InnerException?.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void SetupSubscription()
        {
            // 创建订阅对象
            _opcSubscription = new Subscription(_opcSession.DefaultSubscription)
            {
                PublishingInterval = 1000, // 发布间隔1秒
                Enabled = true
            };

            // 创建trigger节点的监控项
            var triggerNodeId = new NodeId("trigger", NamespaceIndex);
            var triggerMonitoredItem = new MonitoredItem(_opcSubscription.DefaultItem)
            {
                StartNodeId = triggerNodeId,
                AttributeId = Attributes.Value,
                MonitoringMode = MonitoringMode.Reporting
            };

            // 绑定数值变化事件
            triggerMonitoredItem.Notification += TriggerNode_ValueChanged;

            // 添加监控项到订阅
            _opcSubscription.AddItem(triggerMonitoredItem);
            // 将订阅添加到Session
            _opcSession.AddSubscription(_opcSubscription);
            // 激活订阅
            _opcSubscription.Create();
        }

        private void TriggerNode_ValueChanged(object sender, MonitoredItemNotificationEventArgs e)
        {
            // 跨线程更新UI,OPC UA回调在非UI线程触发
            if (InvokeRequired)
            {
                Invoke(new Action(() => TriggerNode_ValueChanged(sender, e)));
                return;
            }

            try
            {
                // 读取Bcode节点的值
                var bcodeNodeId = new NodeId("Bcode", NamespaceIndex);
                var bcodeValue = _opcSession.ReadValue(bcodeNodeId).Value.ToString();

                // 执行数据库查询(将你的已有数据库代码放在此处)
                // var dbResult = YourDatabaseQueryMethod(bcodeValue);

                // 假设查询结果得到OrderId和AreaID的值
                string orderId = "ORD-001";
                string areaId = "AREA-A01";

                // 更新服务器上的OrderId节点
                var orderIdNodeId = new NodeId("OrderId", NamespaceIndex);
                _opcSession.WriteValue(orderIdNodeId, new Variant(orderId));

                // 更新服务器上的AreaID节点
                var areaIdNodeId = new NodeId("AreaID", NamespaceIndex);
                _opcSession.WriteValue(areaIdNodeId, new Variant(areaId));

                MessageBox.Show($"处理完成:Bcode={bcodeValue}\n更新OrderId={orderId},AreaID={areaId}", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"处理失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 清理资源
            _opcSubscription?.Delete();
            _opcSession?.Close();
            _opcSession?.Dispose();
        }
    }
}

关键注意事项

  • 命名空间索引:必须替换为你的OPC UA服务器对应节点的命名空间索引,可通过UA客户端工具(如UA Expert)查看节点完整ID。
  • 证书配置:生产环境禁止启用AutoAcceptUntrustedCertificates,需配置合法客户端证书并导入服务器信任列表。
  • 线程安全:OPC UA回调事件在非UI线程触发,更新WinForms控件时必须使用Invoke跨线程操作,避免UI异常。
  • 节点名称验证:确保代码中使用的节点名称(trigger、Bcode等)与服务器节点完全一致,区分大小写。

内容的提问来源于stack exchange,提问作者Hamza M. S. Abazeed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:57:52