# Einführung

> Konzept: Die Konzepte, die jede Client-Entwicklung mit dem OPC UA .NET SDK voraussetzt: Verbindungsaufbau, Verbindungsparameter, Endpunkte und Sicherheit.

## Die Verbindung zum Server

### Verbinden

Das passiert beim Aufruf der Methode `Connect`:

1. Der Client prüft, ob eine Serveradresse festgelegt ist (Eigenschaft `ServerAddress`). Wenn sie fehlt, löst `Connect` eine `InvalidOperationException` aus.
2. Der Client ändert seinen Status (Eigenschaft `OpcClient.State`) auf den Wert `Connecting`. Wenn sich der Client nicht im Status `Created` oder `Disconnected` befindet, bleibt der Aufruf ohne Wirkung.
3. Der Client prüft seine Konfiguration auf Gültigkeit und Schlüssigkeit.
4. Anschließend sucht der Client einen passenden Endpunkt (engl. Endpoint). Dazu verwendet er die Klasse `OpcDiscoveryClient`. Er vergleicht die Endpunkte mit der gewünschten Endpunktkonfiguration und wählt den Endpunkt aus, der der Konfiguration entspricht oder zumindest genügt. Nach welchen Kriterien der Client einen Endpunkt auswählt, hängt von seinen Einstellungen ab. Die Kriterien beschreibt der Abschnitt [Verbindungsparameter](https://www.traeger.de/docs/development/opcua/client/introduction#verbindungsparameter).
5. Danach erstellt der Client die Konfiguration für eine neue Sitzung.
6. Der Client prüft die Instanzzertifikate:
   - das Zertifikat des Clients (je nach verwendeter Sicherheitskonfiguration)
   - das Zertifikat des Servers (das Zertifikat, das der Endpunkt bereitstellt)
7. Schließlich erstellt der Client einen Channel, der als Verbindung zwischen Client und Server dient.
8. Über den Channel versucht der Client, eine Sitzung zu erstellen.
9. Nachdem weitere Sitzungsdaten ausgetauscht und geprüft sind, aktiviert der Client die Sitzung.
10. Der Client ruft die verfügbaren Namespaces ab.
11. Der Client richtet die Überwachung der Verbindung ein:
    - KeepAlive-Tracking, um Verbindungsabbrüche zu erkennen
    - Notification-Tracking, um Benachrichtigungen zu empfangen
12. Wenn die Auflösung von Datentypen aktiviert ist (zum Beispiel über `OpcClient.UseDynamic`), lädt der Client noch das Typsystem des Servers.
13. Der Client ändert seinen Status (Eigenschaft `OpcClient.State`) auf den Wert `Connected`.

Wenn einer der Schritte fehlschlägt, kehrt der Client in seinen vorherigen Status zurück.

### Trennen

Das passiert beim Aufruf der Methode `Disconnect`:

1. Der Client ändert seinen Status (Eigenschaft `OpcClient.State`) auf den Wert `Disconnecting`.
2. Der Client gibt alle erworbenen Ressourcen wieder frei, zum Beispiel File-Handles zu Datei-Nodes.
3. Der Client beendet die Überwachung der Verbindung und bricht einen laufenden Versuch ab, die Verbindung wiederherzustellen. Er entfernt die Subscriptions aus `OpcClient.Subscriptions`.
4. Der Client beendet die aktive Sitzung.
5. Der Client schließt den Channel, den er beim Verbinden erstellt hat, und verwirft ihn.
6. Der Client ändert seinen Status (Eigenschaft `OpcClient.State`) auf den Wert `Disconnected`.

### Verbindungsabbrüche erkennen

Die **Abbrucherkennung** (`BreakDetection`) erkennt Abbrüche der Verbindung zum Server. Sie verwendet dafür das KeepAlive-Verfahren: Der Client sendet in regelmäßigen Abständen eine KeepAlive-Anfrage an den Server, um die Verbindung zu prüfen und aufrechtzuerhalten. Den Abstand legt die Eigenschaft `OpcClient.KeepAlive.Interval` fest, standardmäßig 5000 Millisekunden. Das Ergebnis der letzten Anfrage stellt die Eigenschaft `OpcClient.KeepAlive` bereit (zum Beispiel `Status`, `ServerState` und `Time`). Jede neue Antwort meldet das Ereignis `OpcClient.KeepAlive.Updated`.

Wenn eine KeepAlive-Anfrage fehlschlägt, geht der Client von einer unterbrochenen Verbindung aus. Dasselbe gilt sofort, ohne das nächste KeepAlive abzuwarten, wenn ein Service-Aufruf als Ganzes mit einem Status fehlschlägt, der auf eine verlorene Verbindung hinweist, zum Beispiel `BadConnectionClosed` oder `BadSessionIdInvalid`. Der Aufruf selbst löst seine Ausnahme trotzdem aus:

1. Der Client ändert seinen Status auf den Wert `Reconnecting` (Ereignis `OpcClient.Reconnecting`).
2. Anschließend versucht er in festen Abständen, die bestehende Sitzung wiederherzustellen. Den Abstand legt die Eigenschaft `OpcClient.ReconnectInterval` fest, standardmäßig 10000 Millisekunden. Wenn das innerhalb der Sitzungsdauer (Eigenschaft `OpcClient.SessionTimeout`) nicht mehr möglich ist, erstellt der Client eine neue Sitzung und legt die Subscriptions darin neu an.
3. Wenn er die bestehende Sitzung wiederherstellt, ändert der Client seinen Status auf den Wert `Reconnected` (Ereignis `OpcClient.Reconnected`). Wenn er eine neue Sitzung erstellt hat, ändert er seinen Status auf den Wert `Connected` (Ereignis `OpcClient.Connected`).
4. Wie lange der Client es höchstens versucht, legt die Eigenschaft `OpcClient.MaxReconnectDuration` fest. Standardmäßig ist sie 0, die Versuche sind also unbegrenzt. Wenn diese Zeit abläuft, bevor ein Versuch gelingt, ändert der Client seinen Status auf den Wert `Disconnected` und löst das Ereignis `OpcClient.BreakDetected` aus. Danach verbindet er sich nicht mehr von selbst, erst ein Aufruf von `Connect` baut die Verbindung neu auf.

Wenn die Eigenschaft `OpcClient.ReconnectInterval` auf den Wert 0 gesetzt ist, versucht der Client nicht, die Verbindung wiederherzustellen. Stattdessen ändert er seinen Status auf den Wert `Disconnected` und löst das Ereignis `OpcClient.BreakDetected` aus. Die Abbrucherkennung ist standardmäßig aktiviert, die Eigenschaft `OpcClient.UseBreakDetection` schaltet sie ein und aus. Wenn sie deaktiviert ist, überwacht der Client die Verbindung nicht. Wie Sie die Abbrucherkennung konfigurieren, zeigt der Abschnitt [Verbindungsüberwachung](https://www.traeger.de/docs/development/opcua/client/configuration#verbindungsuberwachung).

### Verbindungsparameter

Damit der Client eine Verbindung zum Server aufbauen kann, legen Sie die richtigen Parameter fest. Der Client benötigt immer die Adresse, unter der der Server erreichbar ist (Eigenschaft `OpcClient.ServerAddress`). Die Adresse ist ein URI (= Uniform Resource Identifier) und liefert dem Client alle wesentlichen Informationen über den Server. Die Serveradresse `opc.tcp://192.168.0.80:4840` enthält zum Beispiel das Schema `opc.tcp`. Das Schema legt fest, über welches Protokoll die Daten wie ausgetauscht werden. Möglich sind `opc.tcp` und `https`. Für OPC UA Server im lokalen Netzwerk empfehlen wir `opc.tcp`. Für Server außerhalb des lokalen Netzwerks kann sich `https` anbieten. Außerdem legt die Adresse fest, dass der Server auf dem Rechner mit der IP-Adresse `192.168.0.80` läuft und auf Anfragen über den Port `4840` wartet. Das ist der Standardport für OPC UA, benutzerdefinierte Portnummern sind ebenfalls möglich. Anstelle der statischen IP-Adresse können Sie auch den DNS-Namen des Rechners verwenden, zum Beispiel `localhost` anstelle von `127.0.0.1`.

Wenn keine Endpoint-Policy festgelegt ist (Eigenschaft `OpcClient.Security.EndpointPolicy`), wählt der Client den Endpunkt automatisch aus. Von den Endpunkten mit dem Schema der Serveradresse nimmt er den mit dem niedrigsten Policy-Level, einer Zahl, die der Server vergibt. Das ist in der Regel ein Endpunkt mit dem Sicherheitsmodus `None`. Möglich sind zudem `Sign` und `SignAndEncrypt`. Wenn der Server keinen solchen Endpunkt anbietet, wählt der Client automatisch den nächsten, zum Beispiel einen mit `Sign`. Dabei übergeht der Client Endpunkte mit dem Sicherheitsmodus `None`, deren Sicherheitsalgorithmus nicht `None` ist, und Endpunkte mit unbekanntem Sicherheitsalgorithmus. Wenn er keinen passenden Endpunkt findet, löst `Connect` eine `OpcException` mit dem Status `BadSecurityChecksFailed` aus.

Die automatische Auswahl lässt sich auf verschlüsselte Endpunkte beschränken (Eigenschaft `OpcClient.Security.UseOnlySecureEndpoints`, standardmäßig deaktiviert). Dann kommen nur Endpunkte mit dem Sicherheitsmodus `SignAndEncrypt` in Frage. Außerdem kann der Client den Endpunkt nach der Vorgabe der OPC Foundation auswählen: Dann gilt der Endpunkt mit dem höchsten Policy-Level automatisch als der beste für den Datenaustausch. Dieses Verhalten ist standardmäßig deaktiviert. Sie aktivieren es über die Eigenschaft `OpcClient.Security.UseHighLevelEndpoint`.

Wenn der Client eine bestimmte Endpoint-Policy erzwingen soll, legen Sie sie über die Eigenschaft `OpcClient.Security.EndpointPolicy` fest. Der Client verwendet dann nur einen Endpunkt mit genau diesem Sicherheitsmodus und Sicherheitsalgorithmus. Mit der Eigenschaft `OpcClient.Security.AutoUpgradeEndpointPolicy` weicht der Client auf den nächstbesseren Endpunkt aus, wenn der Server die festgelegte Policy nicht anbietet. Welchen Endpunkt der Client tatsächlich verwendet, liefert die Eigenschaft `OpcClient.UsedEndpoint`.

Wenn der Server eine Zugriffssteuerung verwendet, zum Beispiel über eine ACL (= Access Control List, also eine Zugriffskontrollliste), muss der Client dem Server gültige Benutzerdaten übermitteln, bevor eine Verbindung zustande kommt. Mit diesen Daten stellt der Server die Identität des Benutzers fest, der den Client bedient. Die Identität des Benutzers lässt sich über ein Benutzername-Passwort-Paar (Klasse `OpcClientIdentity`) oder über ein Zertifikat (Klasse `OpcCertificateIdentity`) ausweisen. Übergeben Sie die Identität dem Client über die Eigenschaft `OpcClient.Security.UserIdentity`. Der Client übermittelt sie dann beim Verbindungsaufbau an den Server. Wie Sie die Identität einer bestehenden Sitzung wechseln, beschreibt der Abschnitt [Benutzer anmelden](https://www.traeger.de/docs/development/opcua/security/client#benutzer-anmelden).

### Endpunkte

Die Endpunkte ergeben sich aus dem Kreuzprodukt der Basis-Adressen des Servers und der Sicherheitsstrategien, die der Server unterstützt. Jede Basis-Adresse ergibt sich aus einem unterstützten Paar aus Schema und Port und dem Host (IP-Adresse oder DNS-Name). Für den Datenaustausch lassen sich mehrere Schemen (möglich sind `opc.tcp` und `https`) auf unterschiedlichen Ports festlegen. Die so verknüpften Strategien (engl. Policies) legen das Vorgehen beim Datenaustausch fest. Jede Policy besteht aus dem Policy-Level, dem Sicherheitsmodus (engl. Security Mode) und dem Sicherheitsalgorithmus (engl. Security Algorithm) und legt damit die Art des sicheren Datenaustauschs fest.

Angenommen, der Server unterstützt zwei Sicherheitsstrategien:

- Security Policy A: Level 0, Sicherheitsmodus `None`, Sicherheitsalgorithmus `None`
- Security Policy B: Level 1, Sicherheitsmodus `Sign`, Sicherheitsalgorithmus `Basic256Sha256`

Dazu kommen drei Basis-Adressen für verschiedene Schemen:

- Basis-Adresse A: `https://mydomain.com/`
- Basis-Adresse B: `opc.tcp://192.168.0.123:4840/`
- Basis-Adresse C: `opc.tcp://192.168.0.123:12345/`

Das Kreuzprodukt ergibt daraus die folgenden Endpunktbeschreibungen:

- Endpunkt 1: Adresse `https://mydomain.com/`, Level 0, Sicherheitsmodus `None`, Sicherheitsalgorithmus `None`
- Endpunkt 2: Adresse `https://mydomain.com/`, Level 1, Sicherheitsmodus `Sign`, Sicherheitsalgorithmus `Basic256Sha256`
- Endpunkt 3: Adresse `opc.tcp://192.168.0.123:4840/`, Level 0, Sicherheitsmodus `None`, Sicherheitsalgorithmus `None`
- Endpunkt 4: Adresse `opc.tcp://192.168.0.123:4840/`, Level 1, Sicherheitsmodus `Sign`, Sicherheitsalgorithmus `Basic256Sha256`
- Endpunkt 5: Adresse `opc.tcp://192.168.0.123:12345/`, Level 0, Sicherheitsmodus `None`, Sicherheitsalgorithmus `None`
- Endpunkt 6: Adresse `opc.tcp://192.168.0.123:12345/`, Level 1, Sicherheitsmodus `Sign`, Sicherheitsalgorithmus `Basic256Sha256`

Den Adressteil des Endpunkts benötigt der Client immer, über den Konstruktor oder über die Eigenschaft `ServerAddress`. Aus den Endpunkten mit dem Schema dieser Adresse wählt der Client standardmäßig den mit dem niedrigsten Level aus. Im Beispiel oben ist das für die Adresse `opc.tcp://192.168.0.123:4840/` der Endpunkt 3. Wenn der Client stattdessen den Endpunkt 4 verwenden soll, legen Sie dessen Policy über die Eigenschaft `OpcClient.Security.EndpointPolicy` fest.

## Zertifikate und Sicherheit

Das SDK soll den Einstieg in OPC UA so einfach wie möglich machen. Deshalb ist die Verbindung zwischen Client und Server ohne weitere Konfiguration des Clients nicht vollständig abgesichert. Sobald Sie den finalen [Spike](https://en.wikipedia.org/wiki/Spike_%28software_development%29) implementiert und getestet haben, sollten Sie sich mit der Sicherheit befassen:

- Wie Zertifikate Client und Server ausweisen, wo sie liegen und wie die Anwendungen sie prüfen, beschreibt die Seite [Zertifikate verstehen](https://www.traeger.de/docs/development/opcua/security/certificates).
- Wie sich Benutzer anmelden und welche Rechte sie erhalten, beschreibt die Seite [Benutzer und Rollen](https://www.traeger.de/docs/development/opcua/security/users-roles).
- Alle Einstellungen für den Produktivbetrieb und eine Checkliste enthält der Abschnitt [Härtung für den Produktivbetrieb](https://www.traeger.de/docs/development/opcua/security/client#hartung-fur-den-produktivbetrieb).
