和田地区网站建设_网站建设公司_Sketch_seo优化
2025/12/23 14:52:14 网站建设 项目流程

 NodeManager.cs - 节点管理核心

using Opc.Ua;
using Opc.Ua.Server;namespace OpcUaServerDemo
{internal class NodeManager : CustomNodeManager2{private FolderState _rootFolder;private string _rootNodeName;public NodeManager(IServerInternal server, ApplicationConfiguration configuration, string rootNodeName, params string[] namespaceUris): base(server, configuration, namespaceUris){_rootNodeName = rootNodeName;}public NodeManager(IServerInternal server, params string[] namespaceUris): base(server, namespaceUris){_rootNodeName = "opcdata"; // 默认值
        }protected override NodeStateCollection LoadPredefinedNodes(ISystemContext context){_rootFolder = CreateFolder(null, null, _rootNodeName);_rootFolder.AddReference(ReferenceTypes.Organizes, true, ObjectIds.ObjectsFolder); // 将节点添加到服务器根节点_rootFolder.EventNotifier = EventNotifiers.SubscribeToEvents;AddRootNotifier(_rootFolder);return new NodeStateCollection(new List<NodeState> { _rootFolder });}public NodeId? GetRootNodeId(){if (_rootFolder != null){return _rootFolder.NodeId;}return null;}public FolderState? GetRootFolder(){return _rootFolder;  // 直接返回保存的根节点对象
        }protected virtual FolderState CreateFolder(NodeState? parent, string? path, string name, string displayName = ""){if (string.IsNullOrWhiteSpace(path))path = parent?.NodeId.Identifier is string id ? id + "/" + name : name;string finalDisplayName = string.IsNullOrEmpty(displayName) ? name : displayName;FolderState folder = new FolderState(parent);folder.SymbolicName = name;folder.ReferenceTypeId = ReferenceTypes.Organizes;folder.TypeDefinitionId = ObjectTypeIds.FolderType;folder.NodeId = new NodeId(path, NamespaceIndex);folder.BrowseName = new QualifiedName(name, NamespaceIndex);folder.DisplayName = new LocalizedText("en", finalDisplayName);folder.WriteMask = AttributeWriteMask.None;folder.UserWriteMask = AttributeWriteMask.None;folder.EventNotifier = EventNotifiers.None;if (parent != null){parent.AddChild(folder);}return folder;}protected virtual BaseDataVariableState CreateVariable(NodeState? parent, string? path, string name, BuiltInType dataType, int valueRank){return CreateVariable(parent, path, name, (uint)dataType, valueRank);}protected virtual BaseDataVariableState CreateVariable(NodeState? parent, string? path, string name, NodeId dataType, int valueRank, string displayName = "", string symbolicName = ""){if (string.IsNullOrWhiteSpace(path))path = parent?.NodeId.Identifier is string id ? id + "/" + name : name;string finalDisplayName = string.IsNullOrEmpty(displayName) ? name : displayName;BaseDataVariableState variable = new BaseDataVariableState(parent);variable.SymbolicName = string.IsNullOrEmpty(symbolicName) ? name : symbolicName;variable.ReferenceTypeId = ReferenceTypes.Organizes;variable.TypeDefinitionId = VariableTypeIds.BaseDataVariableType;variable.NodeId = new NodeId(path, NamespaceIndex);variable.BrowseName = new QualifiedName(name, NamespaceIndex);variable.DisplayName = new LocalizedText("cn", finalDisplayName);variable.WriteMask = AttributeWriteMask.None;variable.UserWriteMask = AttributeWriteMask.None;variable.DataType = dataType;variable.ValueRank = valueRank;variable.AccessLevel = AccessLevels.CurrentReadOrWrite;variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;variable.Historizing = false;variable.Value = Opc.Ua.TypeInfo.GetDefaultValue(dataType, valueRank, Server.TypeTree);variable.StatusCode = StatusCodes.Good;variable.Timestamp = DateTime.UtcNow;if (valueRank == ValueRanks.OneDimension){variable.ArrayDimensions = new ReadOnlyList<uint>(new List<uint> { 0 });}else if (valueRank == ValueRanks.TwoDimensions){variable.ArrayDimensions = new ReadOnlyList<uint>(new List<uint> { 0, 0 });}if (parent != null){parent.AddChild(variable);}return variable;}public void UpdateValue(NodeId nodeId, object value){var variable = (BaseDataVariableState)FindPredefinedNode(nodeId, typeof(BaseDataVariableState));if (variable != null){variable.Value = value;variable.Timestamp = DateTime.UtcNow;variable.ClearChangeMasks(SystemContext, false);}}public void ClearNodeChangeMasks(NodeState node, bool includeChildren = false){node.ClearChangeMasks(SystemContext, includeChildren);}public NodeId AddFolder(NodeId parentId, string? path, string name, string displayName = ""){var node = Find(parentId);if (node is null){Console.WriteLine("父级节点不存在");return null;}var newNode = CreateFolder(node, path, name, displayName);AddPredefinedNode(SystemContext, newNode);return newNode.NodeId;}public NodeId AddVariable(NodeId parentId, string? path, string name, BuiltInType dataType, int valueRank){return AddVariable(parentId, path, name, (uint)dataType, valueRank);}public NodeId AddVariable(NodeId parentId, string? path, string name, NodeId dataType, int valueRank, string displayName = "", string symbolicName = ""){var node = Find(parentId);if (node is null){Console.WriteLine("父级节点不存在");return null;}var newNode = CreateVariable(node, path, name, dataType, valueRank, displayName, symbolicName);AddPredefinedNode(SystemContext, newNode);return newNode.NodeId;}}
}

NodeManagerFactory.cs - 工厂模式封装

using Opc.Ua;
using Opc.Ua.Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace OpcUaServerDemo
{internal class NodeManagerFactory : INodeManagerFactory{public NodeManager? NodeManager { get; private set; }public StringCollection NamespacesUris => new StringCollection() { "http://opcfoundation.org/OpcUaServer" };private string _rootNodeName;public NodeManagerFactory(string rootNodeName = "opcdata"){_rootNodeName = rootNodeName;}public INodeManager Create(IServerInternal server, ApplicationConfiguration configuration){if (NodeManager != null)return NodeManager;NodeManager = new NodeManager(server, configuration, _rootNodeName, NamespacesUris.ToArray());return NodeManager;}}
}

OpcUaServer.cs - 服务器扩展

using Opc.Ua;
using Opc.Ua.Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;namespace OpcUaServerDemo
{public partial class OpcUaServer : StandardServer{private static readonly object s_statusLock = new object();/// <summary>/// Initializes the server before it starts up./// </summary>/// <remarks>/// This method is called before any startup processing occurs. The sub-class may update the /// configuration object or do any other application specific startup tasks./// </remarks>protected async override void OnServerStarting(ApplicationConfiguration configuration){Utils.Trace("The server is starting.");base.OnServerStarting(configuration);// it is up to the application to decide how to validate user identity tokens.// this function creates validator for X509 identity tokens.
            CreateUserIdentityValidators(configuration);}/// <summary>/// Called after the server has been started./// </summary>protected override void OnServerStarted(IServerInternal server){base.OnServerStarted(server);// request notifications when the user identity is changed. all valid users are accepted by default.server.SessionManager.ImpersonateUser += new ImpersonateEventHandler(SessionManager_ImpersonateUser);try{// allow a faster sampling interval for CurrentTime node.//server.UpdateServerStatus(val => val.Variable.CurrentTime.MinimumSamplingInterval = 250);lock (s_statusLock){server.Status.Variable.CurrentTime.MinimumSamplingInterval = 250;}}catch{ }}#region User Validation Functionsprivate ICertificateValidator m_userCertificateValidator;/// <summary>/// Creates the objects used to validate the user identity tokens supported by the server./// </summary>private void CreateUserIdentityValidators(ApplicationConfiguration configuration){for (int ii = 0; ii < configuration.ServerConfiguration.UserTokenPolicies.Count; ii++){UserTokenPolicy policy = configuration.ServerConfiguration.UserTokenPolicies[ii];// create a validator for a certificate token policy.if (policy.TokenType == UserTokenType.Certificate){// check if user certificate trust lists are specified in configuration.if (configuration.SecurityConfiguration.TrustedUserCertificates != null &&configuration.SecurityConfiguration.UserIssuerCertificates != null){CertificateValidator certificateValidator = new CertificateValidator();certificateValidator.Update(configuration.SecurityConfiguration);certificateValidator.Update(configuration.SecurityConfiguration.UserIssuerCertificates,configuration.SecurityConfiguration.TrustedUserCertificates,configuration.SecurityConfiguration.RejectedCertificateStore);// set custom validator for user certificates.m_userCertificateValidator = certificateValidator.GetChannelValidator();}}}}/// <summary>/// Called when a client tries to change its user identity./// </summary>private void SessionManager_ImpersonateUser(Session session, ImpersonateEventArgs args){// check for a user name token.UserNameIdentityToken userNameToken = args.NewIdentity as UserNameIdentityToken;if (userNameToken != null){args.Identity = VerifyPassword(userNameToken);// set AuthenticatedUser role for accepted user/password authentication
                args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_AuthenticatedUser);if (args.Identity is SystemConfigurationIdentity){// set ConfigureAdmin role for user with permission to configure server
                    args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_ConfigureAdmin);args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_SecurityAdmin);}return;}// check for x509 user token.X509IdentityToken x509Token = args.NewIdentity as X509IdentityToken;if (x509Token != null){VerifyUserTokenCertificate(x509Token.Certificate);args.Identity = new UserIdentity(x509Token);Utils.Trace("X509 Token Accepted: {0}", args.Identity.DisplayName);// set AuthenticatedUser role for accepted certificate authentication
                args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_AuthenticatedUser);return;}// allow anonymous authentication and set Anonymous role for this authenticationargs.Identity = new UserIdentity();args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_Anonymous);}/// <summary>/// Validates the password for a username token./// </summary>private IUserIdentity VerifyPassword(UserNameIdentityToken userNameToken){var userName = userNameToken.UserName;var password = userNameToken.DecryptedPassword;if (String.IsNullOrEmpty(userName)){// an empty username is not accepted.throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid,"Security token is not a valid username token. An empty username is not accepted.");}if (String.IsNullOrEmpty(password)){// an empty password is not accepted.throw ServiceResultException.Create(StatusCodes.BadIdentityTokenRejected,"Security token is not a valid username token. An empty password is not accepted.");}// User with permission to configure serverif (userName == "sysadmin" && password == "sysadmin"){return new SystemConfigurationIdentity(new UserIdentity(userNameToken));}// standard users for CTT verificationif (!((userName == "user1" && password == "password") ||(userName == "user2" && password == "password1"))){// construct translation object with default text.TranslationInfo info = new TranslationInfo("InvalidPassword","en-US","Invalid username or password.",userName);// create an exception with a vendor defined sub-code.throw new ServiceResultException(new ServiceResult(StatusCodes.BadUserAccessDenied,"InvalidPassword",LoadServerProperties().ProductUri,new LocalizedText(info)));}return new UserIdentity(userNameToken);}/// <summary>/// Verifies that a certificate user token is trusted./// </summary>private void VerifyUserTokenCertificate(X509Certificate2 certificate){try{if (m_userCertificateValidator != null){m_userCertificateValidator.Validate(certificate);}else{CertificateValidator.Validate(certificate);}}catch (Exception e){TranslationInfo info;StatusCode result = StatusCodes.BadIdentityTokenRejected;ServiceResultException se = e as ServiceResultException;if (se != null && se.StatusCode == StatusCodes.BadCertificateUseNotAllowed){info = new TranslationInfo("InvalidCertificate","en-US","'{0}' is an invalid user certificate.",certificate.Subject);result = StatusCodes.BadIdentityTokenInvalid;}else{// construct translation object with default text.info = new TranslationInfo("UntrustedCertificate","en-US","'{0}' is not a trusted user certificate.",certificate.Subject);}// create an exception with a vendor defined sub-code.throw new ServiceResultException(new ServiceResult(result,info.Key,LoadServerProperties().ProductUri,new LocalizedText(info)));}}#endregion}
}

RunOpcServer.cs - 业务逻辑

using Opc.Ua;
using Opc.Ua.Configuration;
using System.Collections.Concurrent;namespace OpcUaServerDemo
{public class RunOpcServer : IDisposable{private Task _serverTask;private CancellationTokenSource _cancellationTokenSource;private System.Timers.Timer _simulationTimer;private ConcurrentDictionary<string, BaseDataVariableState> _nodeDic = new ConcurrentDictionary<string, BaseDataVariableState>();public RunOpcServer(){_cancellationTokenSource = new CancellationTokenSource();// 启动服务器任务并保存引用_serverTask = StartServerAsync(_cancellationTokenSource.Token);}private async Task StartServerAsync(CancellationToken cancellationToken){try{var rootNodeName = "opcdata";// 启动OPC UA服务器ApplicationInstance application = new ApplicationInstance();application.ConfigSectionName = "OpcUaServer";application.LoadApplicationConfiguration(false);bool certOk = application.CheckApplicationInstanceCertificate(false, 0).Result;if (!certOk){Console.WriteLine("警告:应用程序证书检查未通过,但服务器将继续启动。");}var server = new OpcUaServer();var nodeManagerFactory = new NodeManagerFactory(rootNodeName);server.AddNodeManager(nodeManagerFactory);// 启动服务器(这会阻塞直到服务器停止)
                application.Start(server).Wait(cancellationToken);Console.WriteLine("OPC UA 服务器已启动!");// 模拟数据var nodeManager = nodeManagerFactory.NodeManager;var root = nodeManager.GetRootFolder();if (root is null){Console.WriteLine($"OPCUA_Server异常:获取根节点失败");return;}var deviceList = new List<string> { "Machine1", "Machine2", "Machine3" };var machineFolderId = nodeManager.AddFolder(root.NodeId, null, "Machine", "Machine");FolderState folder = nodeManager.Find(machineFolderId) as FolderState;foreach (var deviceName in deviceList){var deviceId = nodeManager.AddFolder(machineFolderId, null, deviceName, deviceName);var device = nodeManager.Find(deviceId) as FolderState;var sensorList = new List<string> { "Sensor1", "Sensor2", "Sensor3" };foreach (var sensorName in sensorList){var variableNodeId = nodeManager.AddVariable(deviceId, null, sensorName, (int)BuiltInType.Int16, ValueRanks.Scalar);BaseDataVariableState variable = nodeManager.FindPredefinedNode(variableNodeId, typeof(BaseDataVariableState)) as BaseDataVariableState;var ok = _nodeDic.TryAdd(deviceName + "_" + sensorName, variable);if (!ok){Console.WriteLine($"添加节点失败:{deviceName}_{sensorName}");}}}_simulationTimer = new System.Timers.Timer(1000);var random = new Random();_simulationTimer.Elapsed += (sender, e) =>{if (cancellationToken.IsCancellationRequested)return;try{foreach (var item in _nodeDic){var node = item.Value;var value = random.Next(1, 1000);node.Value = value;node.Timestamp = DateTime.Now;nodeManager.ClearNodeChangeMasks(node, false);}}catch (Exception ex){Console.WriteLine($"更新节点数据出错: {ex.Message}");}};_simulationTimer.Start();// 等待取消令牌,保持服务器运行await Task.Delay(Timeout.Infinite, cancellationToken);}catch (OperationCanceledException){Console.WriteLine("服务器正在停止...");}catch (Exception ex){Console.WriteLine($"服务器发生错误: {ex.Message}");}finally{_simulationTimer?.Stop();_simulationTimer?.Dispose();Console.WriteLine("服务器已停止。");}}public void Stop(){_cancellationTokenSource?.Cancel();_serverTask?.Wait(5000);}public void Dispose(){Stop();_cancellationTokenSource?.Dispose();_simulationTimer?.Dispose();}}
}

 

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询