Anleitung
Werte gebündelt verarbeiten
Tausende Werte mit einem Aufruf lesen, schreiben und abonnieren: wie das SDK große Anfragen an die Grenzen des Servers anpasst und was sich wann lohnt.
Anleitung
Werte gebündelt verarbeiten
Jeder Aufruf von ReadNode oder WriteNode ist eine eigene Anfrage an den Server mit eigener Netzwerklaufzeit. Wer viele Werte in einer Schleife einzeln liest, verliert dadurch schnell Sekunden. Die Methoden ReadNodes, WriteNodes und SubscribeNodes nehmen stattdessen beliebig viele Befehle in einem Aufruf an. Das SDK teilt sie selbst so auf, dass der Server sie annimmt, und fügt die Antworten in der Reihenfolge der Befehle wieder zusammen.
Viele Werte mit einem Aufruf lesen
Beteiligte TypenOpcClientOpcReadNodeOpcValue
Die Ergebnisse stehen in derselben Reihenfolge wie die Befehle. Werten Sie den Status jedes Werts einzeln aus. Ein ungültiger Node bricht den Aufruf nicht ab:
var commands = new OpcReadNode[5000];
for (int index = 0; index < commands.Length; index++)
commands[index] = new OpcReadNode("ns=2;s=Sensors/Sensor" + (index + 1));
IEnumerable<OpcValue> values = client.ReadNodes(commands);Dim commands = New OpcReadNode(4999) {}
For index As Integer = 0 To commands.Length - 1
commands(index) = New OpcReadNode("ns=2;s=Sensors/Sensor" & (index + 1))
Next
Dim values As IEnumerable(Of OpcValue) = client.ReadNodes(commands)Viele Werte mit einem Aufruf schreiben
Beteiligte TypenOpcClientOpcWriteNodeOpcStatusOpcStatusCollection
Auch beim Schreiben gibt es je Befehl ein Ergebnis. Über den Index ordnen Sie jedem Ergebnis den zugehörigen Befehl zu:
var commands = new OpcWriteNode[5000];
for (int index = 0; index < commands.Length; index++)
commands[index] = new OpcWriteNode("ns=2;s=Setpoints/Setpoint" + (index + 1), value: 0.0);
OpcStatusCollection results = client.WriteNodes(commands);
for (int index = 0; index < results.Count; index++) {
if (results[index].IsBad)
Console.WriteLine("{0}: {1}", commands[index].NodeId, results[index].Description);
}Dim commands = New OpcWriteNode(4999) {}
For index As Integer = 0 To commands.Length - 1
commands(index) = New OpcWriteNode("ns=2;s=Setpoints/Setpoint" & (index + 1), value:=0.0)
Next
Dim results As OpcStatusCollection = client.WriteNodes(commands)
For index As Integer = 0 To results.Count - 1
If results(index).IsBad Then
Console.WriteLine("{0}: {1}", commands(index).NodeId, results(index).Description)
End If
NextWie das SDK große Anfragen aufteilt
Beteiligte TypenOpcClientOpcClientServices
Server begrenzen, wie viele Nodes eine einzelne Anfrage enthalten darf, und melden diese Grenzen unter Server/ServerCapabilities/OperationLimits. Wenn ein Aufruf mehr als einen Befehl enthält, geht der Client so vor:
- Beim ersten solchen Aufruf liest er die Grenze des Servers für den jeweiligen Dienst (
MaxNodesPerRead,MaxNodesPerWrite,MaxNodesPerBrowseundMaxNodesPerTranslateBrowsePathsToNodeIds). Wenn der Server keine Grenze meldet (0), verwendet der Client 1000. - Wenn für den Dienst eine eigene Grenze gesetzt ist, gilt der kleinere der beiden Werte.
- Der Client merkt sich den Wert und teilt alle weiteren Aufrufe danach auf mehrere Anfragen auf. Die Antworten fügt er in der Reihenfolge der Befehle zusammen.
Das gilt für ReadNodes, WriteNodes, das Browsen und TranslatePaths. Eine eigene, niedrigere Grenze ist sinnvoll, wenn einzelne Anfragen kürzer dauern sollen oder der Server trotz seiner gemeldeten Grenze an Antwortgrößen scheitert:
client.Services.ReadNodes.MaxNodesPerRead = 500;
client.Services.WriteNodes.MaxNodesPerWrite = 500;
client.Services.Browse.MaxNodesPerBrowse = 100;client.Services.ReadNodes.MaxNodesPerRead = 500
client.Services.WriteNodes.MaxNodesPerWrite = 500
client.Services.Browse.MaxNodesPerBrowse = 100Welche Grenze der Client tatsächlich verwendet, zeigt die zugehörige Eigenschaft mit dem Präfix Used. Sie ist null, solange noch kein Aufruf mit mehreren Befehlen stattgefunden hat:
uint? nodesPerRead = client.Services.ReadNodes.UsedMaxNodesPerRead;Dim nodesPerRead As UInteger? = client.Services.ReadNodes.UsedMaxNodesPerReadUnabhängig von der Anzahl der Nodes begrenzt der Client die Größe der übertragenen Daten. Wie sich diese Grenzen erhöhen lassen, beschreibt der Abschnitt Grenzen der Datenübertragung.
Viele Nodes abonnieren
Beteiligte TypenOpcClientOpcSubscribeDataChangeOpcSubscriptionOpcMonitoredItem
Wenn sich die Werte im Verhältnis zum Leseintervall selten ändern, ist eine Subscription günstiger als zyklisches Lesen, denn der Server meldet nur Änderungen. SubscribeNodes legt alle MonitoredItems in einer Subscription an. Im Handler ist der sender das MonitoredItem. Über dessen NodeId ordnen Sie die Benachrichtigung zu:
var commands = new OpcSubscribeDataChange[1000];
for (int index = 0; index < commands.Length; index++) {
commands[index] = new OpcSubscribeDataChange(
"ns=2;s=Sensors/Sensor" + (index + 1),
HandleDataChanged);
}
OpcSubscription subscription = client.SubscribeNodes(commands);
...
private static void HandleDataChanged(
object sender,
OpcDataChangeReceivedEventArgs e)
{
OpcMonitoredItem item = (OpcMonitoredItem)sender;
Console.WriteLine("{0}: {1}", item.NodeId, e.Item.Value);
}Dim commands = New OpcSubscribeDataChange(999) {}
For index As Integer = 0 To commands.Length - 1
commands(index) = New OpcSubscribeDataChange( _
"ns=2;s=Sensors/Sensor" & (index + 1), _
AddressOf HandleDataChanged)
Next
Dim subscription As OpcSubscription = client.SubscribeNodes(commands)
...
Private Shared Sub HandleDataChanged( _
ByVal sender As Object, _
ByVal e As OpcDataChangeReceivedEventArgs)
Dim item As OpcMonitoredItem = CType(sender, OpcMonitoredItem)
Console.WriteLine("{0}: {1}", item.NodeId, e.Item.Value)
End SubDie passende Zugriffsart wählen
| Situation | Empfehlung |
|---|---|
| Werte werden einmalig oder selten benötigt | ReadNodes mit allen Nodes in einem Aufruf |
| dieselben Nodes werden zyklisch gelesen oder geschrieben | Nodes registrieren und mit den registrierten Identifiern ReadNodes oder WriteNodes aufrufen, siehe Häufig gelesene Nodes registrieren |
| Werte ändern sich selten, die Anwendung reagiert auf Änderungen | Subscription mit allen Nodes über SubscribeNodes, siehe Subscriptions |
| sehr große Einzelwerte (Binärdaten) | Werte als Stream lesen, siehe Große Binärwerte als Stream |
| Nodes sind nur über ihren Pfad bekannt | einmal mit TranslatePaths auflösen, siehe Nodes über Pfade finden |

