如何使用.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
相关产品推荐
相关产品推荐

