opc服务端

文章详细描述了一个名为OpcUaServer的类,它负责OPCUA服务器的配置,包括用户认证、证书管理、节点管理以及服务器启动和停止。类中涉及的方法如LoadAsync用于加载应用配置,CheckCertificateAsync用于检查并更新证书,确保服务器的安全性。
摘要由CSDN通过智能技术生成

OpcUaServer.cs

using Opc.Ua;
using Opc.Ua.Configuration;
using Opc.Ua.Server;
using System.Security.Cryptography.X509Certificates;

namespace OpcServerCore.Util
{
    public class OpcUaServer : StandardServer
    {  
        public ApplicationInstance Application { get; private set; } 

        public bool AutoAccept { get; set; }

        /// <summary>
        /// 认证方式
        /// </summary>
        public UserTokenType UserTokenType { get; set; }

        /// <summary>
        /// 用户名
        /// </summary>
        public string UserName { get; set; } = "admin";

        /// <summary>
        /// 密码
        /// </summary>
        public string Password { get; set; } = "123456";

        ICertificateValidator m_userCertificateValidator;

        public OpcUaNodeManager OpcuaNode1 { get; set; }

        protected override MasterNodeManager CreateMasterNodeManager(IServerInternal server, ApplicationConfiguration configuration)
        {
            OpcuaNode1 = new OpcUaNodeManager(server, configuration);

            List<INodeManager> nodeManagers = new List<INodeManager>();
            nodeManagers.Add(OpcuaNode1);

            return new MasterNodeManager(server, configuration, null, nodeManagers.ToArray());
        }

        public async Task LoadAsync(string applicationName, string configSectionName)
        {
            try
            {
                CertificatePasswordProvider passwordProvider = new CertificatePasswordProvider(Password);

                Application = new ApplicationInstance
                {
                    ApplicationName = applicationName,
                    ApplicationType = ApplicationType.Server,
                    ConfigSectionName = configSectionName,
                    CertificatePasswordProvider = passwordProvider
                };

                await Application.LoadApplicationConfiguration(false);
            }
            catch (Exception ex)
            {
                throw new Exception($"Load async error: {ex.Message}", ex);
            }
        }
         
        public async Task CheckCertificateAsync(bool renewCertificate)
        {
            try
            {
                ApplicationConfiguration config = Application.ApplicationConfiguration;

                if (renewCertificate)
                {
                    await Application.DeleteApplicationInstanceCertificate();
                }

                bool haveAppCertificate = await Application.CheckApplicationInstanceCertificate(false, minimumKeySize: 0);
                if (!haveAppCertificate)
                {
                    throw new Exception("Application instance certificate invalid!");
                }

                if (!config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
                {
                    config.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation);
                }

                // 指定认证方式
                config.ServerConfiguration.UserTokenPolicies.Clear();
                UserTokenPolicy utp = new UserTokenPolicy();
                utp.TokenType = UserTokenType;
                utp.PolicyId = utp.TokenType.ToString();
                config.ServerConfiguration.UserTokenPolicies.Add(utp);

                for (int ii = 0; ii < config.ServerConfiguration.UserTokenPolicies.Count; ii++)
                {
                    UserTokenPolicy policy = config.ServerConfiguration.UserTokenPolicies[ii];

                    if (policy.TokenType == UserTokenType.Certificate)
                    { 
                        if (config.SecurityConfiguration.TrustedUserCertificates != null && config.SecurityConfiguration.UserIssuerCertificates != null)
                        {
                            CertificateValidator certificateValidator = new CertificateValidator();
                            certificateValidator.Update(config.SecurityConfiguration).Wait();
                            certificateValidator.Update(config.SecurityConfiguration.UserIssuerCertificates, config.SecurityConfiguration.TrustedUserCertificates, config.SecurityConfiguration.RejectedCertificateStore);
                            m_userCertificateValidator = certificateValidator.GetChannelValidator();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"CheckCertificateAsync: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// Create server instance and add node managers.
        /// </summary>
        public void Create(IList<INodeManagerFactory> nodeManagerFactories)
        {
            try
            {
                if (nodeManagerFactories != null)
                {
                    foreach (INodeManagerFactory factory in nodeManagerFactories)
                    {
                        this.AddNodeManager(factory);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Create Node manager Factories: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// Start the server.
        /// </summary>
        public async Task StartAsync()
        {
            try
            { 
                await Application.Start(this); 

                this.CurrentInstance.SessionManager.ImpersonateUser += new ImpersonateEventHandler(ImpersonateUser);
                this.CurrentInstance.SessionManager.SessionActivated += EventStatus;
                this.CurrentInstance.SessionManager.SessionClosing += EventStatus;
                this.CurrentInstance.SessionManager.SessionCreated += EventStatus;
            }
            catch (Exception ex)
            {
                throw new Exception($"Start async: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// Stops the server.
        /// </summary>
        public async Task StopAsync()
        {
            try
            {
                this.Stop();
            }
            catch (Exception ex)
            {
                throw new Exception($"Stop async: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// The certificate validator is used
        /// if auto accept is not selected in the configuration.
        /// </summary>
        private void CertificateValidator_CertificateValidation(CertificateValidator validator, CertificateValidationEventArgs e)
        {
            if (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted)
            {
                if (AutoAccept)
                {
                    Logger.Info($"Accepted Certificate: [{e.Certificate.Subject}] [{e.Certificate.Thumbprint}]");
                    e.Accept = true;
                    return;
                }
            }
            Logger.Info($"Rejected Certificate: {e.Error} [{e.Certificate.Subject}] [{e.Certificate.Thumbprint}]");
        }

        private void EventStatus(Session session, SessionEventReason reason)
        { 
             
        }

        private void ImpersonateUser(Session session, ImpersonateEventArgs args)
        { 
            UserNameIdentityToken? userNameToken = args.NewIdentity as UserNameIdentityToken;

            if (userNameToken != null)
            {
                args.Identity = VerifyPassword(userNameToken);
                return;
            }

            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);
                return;
            }
        }

        /// <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))
            {
                throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid, "Security token is not a valid username token. An empty username is not accepted.");
            }

            if (string.IsNullOrEmpty(password))
            {
                throw ServiceResultException.Create(StatusCodes.BadIdentityTokenRejected, "Security token is not a valid username token. An empty password is not accepted.");
            }

            if (!(userName == "admin" && password == "123456"))
            {
                TranslationInfo info = new TranslationInfo("InvalidPassword", "en-US", "Invalid username or password.", userName); 
                throw new ServiceResultException(new ServiceResult(StatusCodes.BadUserAccessDenied, "InvalidPassword", "http://opcfoundation.org/Quickstart/ReferenceServer/v1.03", 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
                {
                    new 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
                {
                    info = new TranslationInfo("UntrustedCertificate", "en-US", "'{0}' is not a trusted user certificate.", certificate.Subject);
                } 
                throw new ServiceResultException(new ServiceResult(result, info.Key, "http://opcfoundation.org/Quickstart/ReferenceServer/v1.04", new LocalizedText(info)));
            }
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 如果 OPC 服务不稳定,可能会导致 Qt 客户无法正常访问服务。你可以考虑以下方法来解决这个问题: 1. 增加重连机制:在 Qt 客户代码中增加重连机制,当与服务连接断开时自动重连,直到连接成功或达到重连次数上限。 2. 增加超时处理:在 Qt 客户代码中增加超时处理机制,当访问服务的请求超时时,自动重新发送请求,直到请求成功或达到重试次数上限。 3. 减少网络负载:如果可能的话,可以尝试减少网络负载,例如缩短数据传输间隔、减小数据包大小等。 4. 优化服务稳定性:最好的方法是优化服务的稳定性,减少服务出现不稳定的情况。可以考虑增加服务监控、提高服务的硬件配置、优化服务代码等措施。 ### 回答2: 当Qt访问OPC服务时,如果服务不稳定,我们可以采取以下几种方法处理: 1. 连接重试:可以在Qt程序中使用连接重试机制来处理不稳定的OPC服务。当连接失败或者连接被中断时,程序可以自动进行连接重试,直到成功建立稳定的连接。 2. 异常处理:在Qt程序中,我们可以添加异常处理机制来捕捉和处理与OPC服务交互过程中可能出现的异常。例如,当读取或写入数据时出现异常,我们可以在代码中添加适当的异常处理代码,例如记录日志、重新连接或提示用户重试等。 3. 优化网络环境:不稳定的OPC服务可能与网络环境有关。我们可以优化网络设置和配置,例如增加带宽、优化网络路由等,以增加与OPC服务之间的稳定性。 4. 定期检查:定期检查OPC服务的稳定性也很重要。我们可以定期检查服务的运行状态、网络连接质量等,并在发现问题时及时采取措施修复或重新配置服务。 5. 使用备份:如果不稳定的OPC服务无法立即修复,我们可以考虑使用备份服务。在Qt程序中,可以配置多个OPC服务,其中一个是备份服务器,当主服务器不稳定时,可以自动切换到备份服务器以保持程序的稳定运行。 总之,当Qt访问不稳定的OPC服务时,我们可以通过连接重试、异常处理、优化网络环境、定期检查以及使用备份等方法来处理,以确保程序与OPC服务的稳定通信。 ### 回答3: 当QT应用程序访问OPC服务时,如果服务不稳定,我们可以采取一些措施来处理这个问题。以下是一些可能的解决方案: 1. 重新连接:当检测到与服务的连接断开时,QT应用程序可以尝试重新连接。可以使用周期性的检测机制来监测与服务的连接状态,并尝试重新建立连接。这样可以确保当服务变得稳定时,应用程序能够恢复与其正常的通信。 2. 错误处理:当与服务的通信发生错误时,QT应用程序应该适当地处理这些错误。可以通过显示错误信息或执行相关的错误处理代码来通知用户。可以记录错误信息以供分析和排查问题。 3. 重试机制:在与服务通信时出现错误时,QT应用程序可以尝试重新发送请求。可以设置一个重试计数器来控制重试的次数,并在重试次数达到一定阈值后停止重试。 4. 容错设计:当服务不稳定时,QT应用程序可以采取一些容错设计来保证系统的可靠性。例如,可以设定一个超时时间,如果在指定的时间内没有收到服务的响应,则认为与服务的通信失败,并采取相应的措施。 5. 日志记录:可以将与服务的通信过程以及与服务交互的各种信息记录到日志文件中。这样可以在分析问题时更容易找出异常并进行排查。 综上所述,当QT应用程序访问不稳定的OPC服务时,可以通过重新连接,错误处理,重试机制,容错设计和日志记录等方法来应对这个问题。这些措施可以提高应用程序的稳定性和可靠性,减少与服务通信故障的影响。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值