Files
dbserver/OpcConnectionTest/Program.cs.fail1
2026-02-21 06:14:35 +09:00

275 lines
10 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
using System.Security.Cryptography.X509Certificates;
namespace OpcConnectionTest
{
class Program
{
[Obsolete]
static async Task Main(string[] args)
{
Console.WriteLine("=== Experion OPC UA Connection Test ===\n");
// ⚠️ Experion 서버 IP 주소 수정
string endpoint = "opc.tcp://192.168.0.20:4840";
string pfxPath = Path.Combine(Directory.GetCurrentDirectory(), "pki/own/certs/OpcTestClient.pfx");
// PFX 파일 존재 여부 먼저 확인
if (!File.Exists(pfxPath))
{
Console.WriteLine($"❌ PFX 파일을 찾을 수 없습니다: {pfxPath}");
Console.WriteLine("\nPress Enter to exit...");
Console.ReadLine();
return;
}
// PFX를 직접 로드 (Exportable 플래그 필수 — OPC UA 서명에 개인키 접근 필요)
X509Certificate2 clientCertificate = new X509Certificate2(
pfxPath,
"",
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
Console.WriteLine($"Server: {endpoint}");
Console.WriteLine($"Certificate: {clientCertificate.Subject}\n");
ISession? session = null;
try
{
// 1. Configuration 생성
var config = new ApplicationConfiguration()
{
ApplicationName = "OPC Test Client",
ApplicationType = ApplicationType.Client,
ApplicationUri = "urn:OpcTestClient",
SecurityConfiguration = new SecurityConfiguration
{
ApplicationCertificate = new CertificateIdentifier
{
StoreType = "Directory",
StorePath = Path.GetFullPath("pki/own"),
SubjectName = "CN=OpcTestClient",
// PFX를 직접 주입 — Directory Store 탐색 없이 이 인증서를 사용
Certificate = clientCertificate
},
TrustedPeerCertificates = new CertificateTrustList
{
StoreType = "Directory",
StorePath = Path.GetFullPath("pki/trusted")
},
TrustedIssuerCertificates = new CertificateTrustList
{
StoreType = "Directory",
StorePath = Path.GetFullPath("pki/issuers")
},
RejectedCertificateStore = new CertificateTrustList
{
StoreType = "Directory",
StorePath = Path.GetFullPath("pki/rejected")
},
AutoAcceptUntrustedCertificates = true,
RejectSHA1SignedCertificates = false,
AddAppCertToTrustedStore = true
},
TransportConfigurations = new TransportConfigurationCollection(),
TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 }
};
await config.ValidateAsync(ApplicationType.Client);
// 인증서 로드 확인 (Find 대신 직접 참조)
var cert = config.SecurityConfiguration.ApplicationCertificate.Certificate;
if (cert == null)
{
Console.WriteLine("❌ [Internal Error] 인증서 주입에 실패했습니다!");
return;
}
Console.WriteLine($"✅ 인증서 로드 성공: {cert.Subject}");
Console.WriteLine($" 유효기간: {cert.NotBefore:yyyy-MM-dd} ~ {cert.NotAfter:yyyy-MM-dd}");
Console.WriteLine($" 개인키 포함: {cert.HasPrivateKey}");
if (!cert.HasPrivateKey)
{
Console.WriteLine("❌ 개인키가 없습니다. PFX 파일 또는 KeyStorageFlags를 확인하세요.");
return;
}
Console.WriteLine("\nStep 1: Discovering endpoints...");
// 2. Endpoint 검색
var endpointConfig = EndpointConfiguration.Create(config);
endpointConfig.OperationTimeout = 10000;
var discoveryClient = await DiscoveryClient.CreateAsync(
new Uri(endpoint),
endpointConfig,
config,
DiagnosticsMasks.None,
CancellationToken.None);
var endpoints = await discoveryClient.GetEndpointsAsync(null);
discoveryClient.Dispose();
if (endpoints == null || endpoints.Count == 0)
{
Console.WriteLine("❌ No endpoints found!");
return;
}
Console.WriteLine($"✅ Found {endpoints.Count} endpoint(s)");
foreach (var ep in endpoints)
{
Console.WriteLine($" - {ep.EndpointUrl} ({ep.SecurityMode})");
}
Console.WriteLine("\nStep 2: Creating session...");
// 3. ConfiguredEndpoint 생성
var selectedEndpoint = endpoints[0];
var configuredEndpoint = new ConfiguredEndpoint(
null,
selectedEndpoint,
EndpointConfiguration.Create(config));
// 4. Session 생성
session = await Session.Create(
config,
configuredEndpoint,
false,
"OPC Test Session",
60000,
new UserIdentity(new AnonymousIdentityToken()),
null);
Console.WriteLine($"✅ Connected!");
Console.WriteLine($" Session ID: {session.SessionId}");
Console.WriteLine("\nStep 3: Reading server info...");
await ReadServerInfoAsync(session);
Console.WriteLine("\nStep 4: Checking redundancy...");
await CheckRedundancyAsync(session);
Console.WriteLine("\nStep 5: Browsing nodes...");
await BrowseNodesAsync(session);
Console.WriteLine("\n✅ All tests completed!");
}
catch (Exception ex)
{
Console.WriteLine($"\n❌ Error: {ex.Message}");
Console.WriteLine($"Type: {ex.GetType().Name}");
if (ex.InnerException != null)
{
Console.WriteLine($"Inner: {ex.InnerException.Message}");
}
}
finally
{
if (session != null)
{
try
{
Console.WriteLine("\nClosing session...");
await session.CloseAsync();
session.Dispose();
Console.WriteLine("✅ Session closed");
}
catch { }
}
}
Console.WriteLine("\nPress Enter to exit...");
Console.ReadLine();
}
static async Task ReadServerInfoAsync(ISession session)
{
try
{
// Server State
var state = await session.ReadValueAsync(
new NodeId(Variables.Server_ServerStatus_State));
Console.WriteLine($" State: {state.Value}");
// Server Time
var time = await session.ReadValueAsync(
new NodeId(Variables.Server_ServerStatus_CurrentTime));
Console.WriteLine($" Time: {time.Value}");
}
catch (Exception ex)
{
Console.WriteLine($" Error: {ex.Message}");
}
}
static async Task CheckRedundancyAsync(ISession session)
{
try
{
var serviceLevel = await session.ReadValueAsync(
new NodeId(Variables.Server_ServiceLevel));
byte level = Convert.ToByte(serviceLevel.Value);
Console.WriteLine($" Service Level: {level}");
if (level >= 200)
Console.WriteLine(" ✅ PRIMARY server");
else if (level > 0)
Console.WriteLine(" ⚠️ SECONDARY server");
else
Console.WriteLine(" STANDALONE");
}
catch (Exception ex)
{
Console.WriteLine($" Error: {ex.Message}");
}
}
static async Task BrowseNodesAsync(ISession session)
{
try
{
var browser = new Browser(session)
{
BrowseDirection = BrowseDirection.Forward,
ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences,
IncludeSubtypes = true,
NodeClassMask = (int)(NodeClass.Object | NodeClass.Variable)
};
var references = await browser.BrowseAsync(ObjectIds.ObjectsFolder);
Console.WriteLine($" Found {references.Count} top-level nodes:");
int count = 0;
foreach (var r in references)
{
Console.WriteLine($" {r.DisplayName} ({r.NodeClass})");
if (++count >= 5)
{
Console.WriteLine($" ... and {references.Count - 5} more");
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine($" Error: {ex.Message}");
}
}
}
}