Módosítási előzmények (csak az első változat, közzétéve: 2026. 11. 01.)
- Első közzététel
Hivatkozás erre a cikkre(DOI: 10.5281/zenodo.23968446)
Ez a cikk a Zenodón van archiválva. Alább egyaránt megtalálja a mindig a legfrissebb változatra mutató DOI-t és az Ön által éppen olvasott változathoz rögzített DOI-t.
Go Komura (2026): Bevezetés az OPC UA-ba ── PLC- és berendezésadatok gyűjtése Windows-alkalmazással. KomuraSoft LLC. https://doi.org/10.5281/zenodo.23968446 https://comcomponent.com/hu/blog/opc-ua-windows-data-collection/
- DOI (legfrissebb változat)
- 10.5281/zenodo.23968446
- DOI (ez a változat)
- 10.5281/zenodo.23968447
Ha PLC-k vagy berendezések adatait gyűjtjük egy Windows-alkalmazásba, és a berendezésnek van OPC UA-szervere, előfordulhat, hogy nem kell gyártónként külön kommunikációt megírnunk. Csatlakozni és értékeket olvasni azonban nem elég. Ha nem ismerjük az értékekkel együtt visszaadott állapotot és időbélyegeket, a változásokról értesítő előfizetést, a tanúsítványokkal történő csatlakozásengedélyezést és a kapcsolatbontás utáni helyreállást, később nem bízhatunk meg a gyűjtött adatokban.
Ez a cikk az OPC UA működésének az adatgyűjtéshez szükséges részeit mutatja be, egy C#-kliens tényleges futtatásának eredményeivel együtt. A kliens az OPC Foundation .NET-es könyvtárát használja, a másik oldalon pedig egy szimulált berendezésszerver áll. Konkrét PLC-n vagy berendezésen nem próbáltam ki. Az egyes berendezések beállításait azok dokumentációjában ellenőrizze.
A GigE Vision- és USB3 Vision-kamerák képeinek gyűjtéséről a „Dropped Frames with GigE Vision and USB3 Vision Cameras”, a soros kommunikációt használó berendezésekről pedig a „Serial Communication App Pitfalls” című cikkben írtam.
Az OPC UA és az OPC Classic különbsége
Az OPC Classic specifikációi a Windows COM/DCOM technológiájával cserélnek adatokat a szoftverkomponensek között. A folyamatadatokat kezelő OPC DA, a riasztásokat kezelő OPC A&E és az előzményadatokat kezelő OPC HDA külön specifikációként van meghatározva1.
Az OPC Foundation 2008-ban tette közzé az OPC UA-t (Unified Architecture). Az OPC UA egy adott platformtól független, szolgáltatásorientált architektúra, amely egységesen kezeli a Classic egyes specifikációinak funkcióit. Az újratervezés okaként az OPC Foundation többek között azt említi, hogy a Microsoft a COM/DCOM helyett a platformfüggetlen megoldásokra kezdett nagyobb hangsúlyt helyezni, hogy a szabványnak a Microsofttól eltérő rendszereken és beágyazott eszközökön is futnia kellett, és hogy biztonságosan kellett csatlakozni tűzfalakon keresztül is1.
Az OPC UA specifikációját az IEC is szabványosította az IEC 62541 sorozatként2. A kommunikációs portot illetően az IANA a 4840/TCP portot opcua-tcp néven tartja nyilván3.
flowchart TB
accTitle: Az OPC Classic és az OPC UA különbsége
accDescr: Az ábra azt mutatja, hogy az OPC Classic a Windows COM és DCOM technológiájára épül, és külön DA, A&E és HDA specifikációra oszlik, az OPC UA pedig ezek funkcióit egyetlen, platformtól független specifikációban egyesíti.
C["OPC Classic"] --> D["COM/DCOM (Windows) felett fut"]
D --> DA["DA, A&E és HDA külön specifikációk"]
DA -->|"Funkciók egyesítése"| U["OPC UA (2008)"]
U --> P["Nem kötődik adott platformhoz"]
P --> S["IEC 62541 szabványként"]
1. ábra: Az OPC Classic a COM/DCOM feletti különálló specifikációkból áll, az OPC UA pedig ezeket egyesíti.
Ha a meglévő berendezésnek csak OPC DA-szervere van, a kliens oldalán a COM/DCOM-ot használó megoldásra van szükség. Ez a cikk csak az OPC UA-val foglalkozik.
Az ábrán a folytonos vonal mindig fennálló kapcsolatot, a szaggatott vonal feltételes kapcsolatot jelöl (a feltételeket a részletoldal kapcsolatonként ismerteti). A kapcsolatok teljes listája (összesen 13, bizonyítékokkal és megbízhatósági szinttel) és a fő fogalmak meghatározása a tudástérkép részletoldalán található (japánul). Adatok: JSON-LD / Turtle
A kipróbált konfiguráció
A következő konfigurációt futtattam.
| Szerep | Amit használtam |
|---|---|
| Kliens | C#, .NET 10 SDK 10.0.114, OPCFoundation.NetStandard.Opc.Ua.Client 2.0.1 NuGet-csomag |
| Szerver | Python 3.13 és asyncua 2.1.0 segítségével készített szimulált berendezés (ugyanazon a gépen, a 4840-es porton) |
| Operációs rendszer | Linux (Windowson nem próbáltam ki a futtatást) |
A kliens könyvtára az OPC Foundation által közzétett .NET-es megvalósítás. A 2.0-s sorozat használatában ugyanannak a tárolónak a Getting started leírását követtem4.
flowchart TB
accTitle: A kipróbált konfiguráció
accDescr: Az ábra egy olyan konfigurációt mutat, amelyben az OPC Foundation .NET-es könyvtárát használó C#-kliens titkosított kapcsolaton csatlakozik a 4840-es porton figyelő, asyncua-val készített szimulált berendezésszerverhez.
A["C#-kliens (LineCollector)"] -->|"opc.tcp, SignAndEncrypt"| B["Szimulált berendezésszerver (asyncua)"]
A -.-> L["Az OPC Foundation .NET-es könyvtára, 2.0.1"]
B -.-> V["A Line1 négy változója"]
2. ábra: Ugyanazon a gépen belül a C#-kliens a szimulált berendezésszerverhez csatlakozott.
A szimulált berendezésszerver
A berendezés helyett egy kis szervert készítettem asyncua-val5. A Line1 nevű objektum alatt négy változó található: a hőmérséklet (Temperature), a gyártott darabszám (PartCount), az üzemállapot (Running) és az alapjel (Setpoint). A hőmérséklet 0,5 másodpercenként, a darabszám 2 másodpercenként változik. Biztonsági beállításként kettőt biztosítottam: titkosítás nélküli kapcsolatot (None), valamint aláírást és titkosítást (Basic256Sha256 SignAndEncrypt módban).
# Működésellenőrzésre szolgáló szimulált berendezés. Nem helyettesíti az éles berendezéseket vagy PLC-ket.
import asyncio, math, random, socket
from pathlib import Path
from cryptography.x509.oid import ExtendedKeyUsageOID
from asyncua import Server, ua
from asyncua.crypto.cert_gen import setup_self_signed_certificate
HERE = Path(__file__).parent
APP_URI = "urn:komurasoft:demo-plc"
async def main():
key, cert = HERE / "server_key.pem", HERE / "server_cert.der"
await setup_self_signed_certificate(
key, cert, APP_URI, socket.gethostname(),
[ExtendedKeyUsageOID.SERVER_AUTH], {"commonName": "DemoPlcServer"})
server = Server()
await server.init()
server.set_endpoint("opc.tcp://0.0.0.0:4840/demo/")
server.set_server_name("DemoPlcServer")
await server.set_application_uri(APP_URI)
server.set_security_policy([
ua.SecurityPolicyType.NoSecurity,
ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
])
await server.load_certificate(str(cert))
await server.load_private_key(str(key))
ns = await server.register_namespace("urn:komurasoft:demo-plc:line1")
line1 = await server.nodes.objects.add_object(ua.NodeId("Line1", ns), "Line1")
temperature = await line1.add_variable(ua.NodeId("Line1.Temperature", ns), "Temperature", 25.0)
part_count = await line1.add_variable(
ua.NodeId("Line1.PartCount", ns), "PartCount", ua.Variant(0, ua.VariantType.UInt32))
await line1.add_variable(ua.NodeId("Line1.Running", ns), "Running", True)
setpoint = await line1.add_variable(ua.NodeId("Line1.Setpoint", ns), "Setpoint", 30.0)
await setpoint.set_writable()
async with server:
print("listening", flush=True)
t, count = 0, 0
while True:
await asyncio.sleep(0.5)
t += 1
value = 25.0 + 2.0 * math.sin(t / 4) + random.uniform(-0.05, 0.05)
await temperature.write_value(round(value, 2))
if t % 4 == 0:
count += 1
await part_count.write_value(ua.Variant(count, ua.VariantType.UInt32))
asyncio.run(main())
Ez a szerver ellenőrzés nélkül elfogadja a csatlakozó kliensek tanúsítványát. Ez tesztbeállítás, és eltér az éles berendezések viselkedésétől.
A C#-kliens
A projektfájlba a következő két csomagot vettem fel.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
</ItemGroup>
</Project>
A kliens sorban csatlakozik, böngészik, olvas, ír és előfizet. Az egyes részek jelentését a következő szakaszok sorra elmagyarázzák.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Client.Subscriptions;
using Opc.Ua.Client.Subscriptions.Streaming;
using MonitoredItemOptions = Opc.Ua.Client.Subscriptions.MonitoredItems.MonitoredItemOptions;
string url = args.Length > 0 ? args[0] : "opc.tcp://localhost:4840/demo/";
int notifications = args.Length > 1 ? int.Parse(args[1]) : 6;
const string LineNamespace = "urn:komurasoft:demo-plc:line1";
HostApplicationBuilder builder = Host.CreateApplicationBuilder();
builder.Logging.SetMinimumLevel(LogLevel.Warning);
builder.Services
.AddOpcUa()
.AddClient(options =>
{
options.ApplicationName = "LineCollector";
options.ApplicationUri = "urn:localhost:LineCollector";
options.ProductUri = "urn:komurasoft:LineCollector";
options.PkiRoot = Path.Combine(AppContext.BaseDirectory, "pki");
})
.AddDiscoveryAndConnect(options =>
{
options.DiscoveryUrl = url;
options.SecurityMode = MessageSecurityMode.SignAndEncrypt;
options.SecurityPolicyUri = SecurityPolicies.Basic256Sha256;
});
using IHost host = builder.Build();
await host.StartAsync();
using var timeout = new CancellationTokenSource(TimeSpan.FromMinutes(2));
CancellationToken ct = timeout.Token;
try
{
var connect = host.Services
.GetRequiredService<Func<CancellationToken, Task<ManagedSession>>>();
ManagedSession session = await connect(ct);
await using (session)
{
Console.WriteLine($"接続: {session.ConfiguredEndpoint?.EndpointUrl}");
// A névtérindexet a szerver határozza meg. Az URI alapján keressük ki, és abból készítjük a NodeId-ket
ushort ns = (ushort)session.NamespaceUris.GetIndex(LineNamespace);
var line1 = new NodeId("Line1", ns);
var temperature = new NodeId("Line1.Temperature", ns);
var partCount = new NodeId("Line1.PartCount", ns);
var setpoint = new NodeId("Line1.Setpoint", ns);
// Böngészés: a Line1 alatti változók listázása
var browser = new Browser(session)
{
BrowseDirection = BrowseDirection.Forward,
ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences,
IncludeSubtypes = true,
NodeClassMask = (uint)NodeClass.Variable,
};
Console.WriteLine("Line1 の変数:");
foreach (ReferenceDescription child in await browser.BrowseAsync(line1, ct))
{
Console.WriteLine($" {child.DisplayName} {child.NodeId}");
}
// Olvasás: nemcsak az értéket, hanem az állapotot és a két időbélyeget is nézzük
DataValue t = await session.ReadValueAsync(temperature, ct);
Console.WriteLine($"Temperature = {t.WrappedValue} 状態 {t.StatusCode}");
Console.WriteLine($" Source {Hms(t.SourceTimestamp)} / Server {Hms(t.ServerTimestamp)}");
// Nem létező csomópont olvasásakor érték helyett Bad állapot jön vissza
try
{
await session.ReadValueAsync(new NodeId("Line1.Pressure", ns), ct);
}
catch (ServiceResultException ex)
{
Console.WriteLine($"Line1.Pressure の読み取り: {ex.StatusCode}");
}
// Írás: a Setpoint értékét 32,5-re állítjuk
var write = new WriteValue
{
NodeId = setpoint,
AttributeId = Attributes.Value,
Value = new DataValue(new Variant(32.5)),
};
WriteResponse wr = await session.WriteAsync(null, new[] { write }, ct);
Console.WriteLine($"Setpoint の書き込み: {wr.Results[0]}");
// Előfizetés: 500 ms-onkénti mintavételt kérünk a szervertől, és értesítést a változásokról
Console.WriteLine($"購読({notifications}件まで):");
await foreach (DataValueChange change in session.DefaultStreaming
.SubscribeDataChangesAsync(new[] { temperature, partCount }, options: new MonitoredItemOptions
{
SamplingInterval = TimeSpan.FromMilliseconds(500),
QueueSize = 5,
}, ct: ct)
.TakeAsync(notifications)
.WithCancellation(ct))
{
DataValue v = change.Value;
string name = change.MonitoredItem?.Name.Split("s=")[^1] ?? "?";
Console.WriteLine($" {Hms(v.SourceTimestamp)} {name,-17} {v.WrappedValue,6} {v.StatusCode}");
}
}
}
catch (ServiceResultException ex)
{
Console.Error.WriteLine($"OPC UA エラー {ex.StatusCode}: {ex.Message}");
Environment.ExitCode = 1;
}
finally
{
await host.StopAsync();
}
static string Hms(DateTimeUtc time) => time.ToDateTime().ToString("HH:mm:ss.fff");
Az első futtatáskor nem sikerült csatlakozni. Ennek okát „A csatlakozás engedélyezése tanúsítványokkal” című szakasz magyarázza el. A szerver tanúsítványának megbízhatóvá tétele utáni kimenet a következő. A könyvtár figyelmeztető naplóbejegyzéseit kihagytam.
接続: opc.tcp://localhost:4840/demo/
Line1 の変数:
Temperature ns=2;s=Line1.Temperature
PartCount ns=2;s=Line1.PartCount
Running ns=2;s=Line1.Running
Setpoint ns=2;s=Line1.Setpoint
Temperature = 23.09 状態 Good [0x00000000]
Source 13:40:51.302 / Server 13:40:51.302
Line1.Pressure の読み取り: BadNodeIdUnknown [0x80340000]
Setpoint の書き込み: Good [0x00000000]
購読(6件まで):
13:40:51.302 Line1.Temperature 23.09 Good [0x00000000]
13:40:50.801 Line1.PartCount 67 Good [0x00000000]
13:40:51.802 Line1.Temperature 23.05 Good [0x00000000]
13:40:52.304 Line1.Temperature 23.07 Good [0x00000000]
13:40:52.806 Line1.Temperature 23.2 Good [0x00000000]
13:40:52.806 Line1.PartCount 68 Good [0x00000000]
Az időpontok UTC szerintiek.
A berendezés adatai csomópontokként jelennek meg a címtérben
Az OPC UA-szerver a birtokában lévő adatokat csomópontok (node-ok) halmazaként teszi közzé. Ezt a halmazt címtérnek (address space) nevezzük. A csomópontoknak különféle fajtái vannak, például a mappákat vagy berendezéseket jelölő objektumok és az értéket tároló változók, a csomópontokat pedig hivatkozások kötik össze. A kliens a Browse szolgáltatással követi a hivatkozásokat, és így deríti fel, milyen csomópontok léteznek6.
A fenti kimenetben a kliens a Line1 objektumtól kiindulva követi a hierarchikus hivatkozásokat, és négy változót talál.
flowchart TB
accTitle: A szimulált berendezés címtere
accDescr: Az ábra azt mutatja, hogy az Objects mappa alatt egy Line1 objektum található, alatta pedig négy változó: Temperature, PartCount, Running és Setpoint.
O["Objects"] --> L["Line1 (objektum)"]
L --> T["Temperature (változó)"]
L --> P["PartCount (változó)"]
L --> R["Running (változó)"]
L --> S["Setpoint (változó, írható)"]
3. ábra: A szimulált berendezés címtere. A kliens a Browse segítségével a hivatkozásokat követve találja meg a csomópontokat.
A NodeId névtérből és azonosítóból áll
A csomópontokat a NodeId azonosítja. A kimenetben szereplő ns=2;s=Line1.Temperature azt jelenti, hogy a névtérindex 2, az azonosító pedig a Line1.Temperature karakterlánc.
A névtér valójában egy URI. A specifikáció szerint a szolgáltatásokon belül a névtér URI-ját szám jelöli, és ez a szám a szerver NamespaceArray tömbjében elfoglalt pozíciónak felel meg. A 0-s index az OPC UA névtere, a http://opcfoundation.org/UA/7.
Ezért az index számát nem érdemes beírni a kódba; ehelyett az URI alapján kell kikeresni. A fenti kód a session.NamespaceUris.GetIndex(LineNamespace) hívással kapja meg az URI-ból a 2-es indexet, és abból készíti el a NodeId-ket.
flowchart TB
accTitle: NodeId előállítása a névtér URI-jából
accDescr: Az ábra azt mutatja, hogy a kliens a névtér URI-ját a szerver NamespaceArray tömbjében kikeresve megkapja az indexet, majd az indexet az azonosítóval kombinálva előállítja a NodeId-t.
U["A névtér URI-ja"] --> A["A szerver NamespaceArray tömbje"]
A --> I["Index (ebben a példában 2)"]
I --> N["NodeId ns=2;s=Line1.Temperature"]
K["Azonosító: Line1.Temperature"] --> N
4. ábra: A névtérindexet az URI alapján keressük ki, és az azonosítóval kombinálva kapjuk a NodeId-t.
Olvasáskor és íráskor az értékkel együtt állapot és időbélyeg is visszajön
A változók értékét a Read és a Write szolgáltatással olvassuk és írjuk8. Olvasáskor nemcsak az érték jön vissza. Egy DataValue nevű struktúra érkezik, amely az értéket, az állapotkódot, a forrásidőbélyeget és a szerveridőbélyeget tartalmazza9.
| Elem | Jelentés |
|---|---|
| Érték | A változó értéke. Ha az állapotkód hibát jelez, az értéket figyelmen kívül kell hagyni, és a szerver null értékre állítja |
| Állapotkód (StatusCode) | Sikerült-e a szervernek megszereznie és szolgáltatnia az értéket |
| SourceTimestamp | Az az időpont, amelyet az adat forrása rendelt az értékhez |
| ServerTimestamp | Az az időpont, amikor a szerver megkapta az értéket, vagy amikor kiderült, hogy az érték helyes |
Az állapotkód felső két bitje Good (sikeres), Uncertain (részben sikeres, egyes célokra esetleg nem használható) vagy Bad (sikertelen) állapotot jelez10. A kimenetben szereplő Good [0x00000000] Good állapotot jelent.
A nem létező Line1.Pressure olvasásakor érték helyett BadNodeIdUnknown [0x80340000] jött vissza. Ennek a könyvtárnak a ReadValueAsync metódusa kivételt dob, ha az állapot Bad4. Ha az értékeket rögzítő rendszer az értékek mellett az állapotkódot is megőrzi, később meg lehet különböztetni a Bad állapot idején rögzített értékeket.
flowchart TB
accTitle: A DataValue tartalma
accDescr: Az ábra azt mutatja, hogy az olvasáskor vagy értesítéskor visszaadott DataValue négy elemet tartalmaz – az értéket, az állapotkódot, a forrásidőbélyeget és a szerveridőbélyeget –, és hogy Bad állapotkód esetén az értéket figyelmen kívül kell hagyni.
D["DataValue"] --> V["Érték"]
D --> S["Állapotkód"]
D --> TS["SourceTimestamp (a forrás időpontja)"]
D --> TV["ServerTimestamp (a szerver időpontja)"]
S -->|"Ha Bad"| X["Az értéket figyelmen kívül hagyjuk"]
5. ábra: Az olvasás eredménye nemcsak az értéket, hanem az állapotkódot és két időbélyeget is tartalmaz.
Íráskor 32,5-öt írtam a Setpoint változóba, és eredményként Good állapotkód jött vissza. Azt, hogy melyik változó írható, a szerver dönti el. Ebben a szimulált szerverben csak a Setpoint írható. Az, hogy a berendezés alapjeleit kívülről át lehessen-e írni, a berendezés biztonsági tervezésének kérdése, ezért ez a cikk nem foglalkozik vele.
Értesítés a változásokról: előfizetés és MonitoredItem
Az értékek változásának követésére az is lehetséges, hogy a kliens rendszeres időközönként ismételten Read hívást küld. Az OPC UA-ban ettől függetlenül van egy olyan mechanizmus is, amely az értékek figyelését a szerverre bízza, és értesítést kér a változásokról. Ez az előfizetés (subscription) és a MonitoredItem.
A MonitoredItem egyetlen figyelt elem, amelynek mintavételi időköze van. A mintavételi időköz a leggyorsabb ütem, amellyel a szerver a forrásból mintát vesz az értékekből, és a specifikáció ezt „best effort” ciklusként írja le11. Ha a minta megfelel a szűrő feltételeinek, értesítés jön létre. Ha nincs megadva szűrő, akkor az érték vagy az állapot változásakor jön értesítés12.
Az értesítések először a MonitoredItem várakozási sorába kerülnek. Előre meg kell határozni, hogy a sor megtelésekor a legrégebbi vagy a legújabb elem kerüljön-e eldobásra, és ha a sor mérete legalább 2, az állapotkódban beáll az eldobást jelző Overflow bit13.
Az előfizetés több MonitoredItemet fog össze, és minden közzétételi időközben elküldi a kliensnek a még el nem küldött értesítéseket. Ha egymás után több cikluson át nincs küldendő értesítés, keep-alive üzenetet küld annak jelzésére, hogy az előfizetés még él14.
flowchart TB
accTitle: Az előfizetés és a MonitoredItem működése
accDescr: Az ábra azt mutatja, hogy a MonitoredItem a mintavételi időközzel mintát vesz a forrás értékéből, a szűrőn átjutott értesítéseket várakozási sorba helyezi, az előfizetés pedig a közzétételi időközzel összegyűjtve elküldi őket a kliensnek, értesítés hiányában pedig keep-alive üzenetet küld.
S["Forrás (a berendezés értéke)"] --> M["MonitoredItem"]
M -->|"Mintavételi időköz"| F["Szűrő (alapértelmezés: az érték vagy az állapot változása)"]
F --> Q["Várakozási sor (megteléskor Overflow)"]
Q --> SUB["Előfizetés"]
SUB -->|"Közzétételi időköz"| C["Kliens"]
SUB -.->|"Ha nincs értesítés"| K["Keep-alive"]
6. ábra: A MonitoredItem mintát vesz és sorba állít, az előfizetés pedig összegyűjtve küldi el az értesítéseket a kliensnek.
A fenti kód 500 ezredmásodperces mintavételi időközzel és 5-ös sormérettel fizet elő a Temperature és a PartCount változóra15. A kimenetben a hőmérséklet nagyjából 0,5 másodpercenként, a darabszám nagyjából 2 másodpercenként érkezik. Az első két értesítés azt az értéket tartalmazta, amelyet az egyes változók az előfizetés kezdetekor tartalmaztak. A darabszámnál szereplő 13:40:50.801 az az időpont, amikor az érték az előfizetés kezdete előtt megváltozott. Mivel az értesítések a forrásidőbélyeget jelenítik meg, nem az értesítés beérkezésének, hanem az érték megváltozásának időpontja látható.
Ismételt olvasás vagy előfizetés
Az ismételt olvasás esetén az időközt a kliens oldalán lehet meghatározni, és a mechanizmus egyszerű. Cserébe minden alkalommal oda-vissza megy egy kérés és egy válasz akkor is, ha az érték nem változott, az időköznél rövidebb változások pedig elsikkadnak. Előfizetéskor a szerver vesz mintát, és csak a változásokat küldi el, így a ritkán változó értékeknél sem nő sokat a forgalom. Előfizetéskor azonban a mintavételi időköznél rövidebb változásokról sem feltétlenül érkezik értesítés. A specifikáció megengedi, hogy a szerver a kértnél gyorsabban vegyen mintát, de nem követeli meg11.
flowchart TB
accTitle: Az ismételt olvasás és az előfizetés különbsége
accDescr: Az ábra azt mutatja, hogy ismételt olvasáskor a kliens határozza meg az időközt, és minden alkalommal kérést küld, előfizetéskor a szerver a mintavételi időközzel mintát vesz, és csak a változásokat küldi el, és hogy mindkét módszer elszalaszthatja az időköznél rövidebb változásokat.
A["Az értékváltozások követése"] --> R["Ismételt olvasás"]
A --> S["Előfizetés"]
R --> R1["A kliens határozza meg az időközt, és minden alkalommal kér"]
S --> S1["A szerver vesz mintát, és csak a változásokat küldi"]
R1 --> X["Az időköznél rövidebb változások elveszhetnek"]
S1 --> X
7. ábra: Mindkét módszernél előfordulhat, hogy az időköznél rövidebb változások nem érzékelhetők.
A csatlakozás engedélyezése tanúsítványokkal
Az OPC UA-kapcsolatban az üzenetek védelmének mértékét a MessageSecurityMode határozza meg. Lehetséges értékei: a védelmet nem nyújtó None, a csak aláíró Sign, valamint az aláíró és titkosító SignAndEncrypt16. Az aláíráshoz és titkosításhoz használt algoritmusok kombinációját a biztonsági házirend (security policy) határozza meg; ez a cikk a Basic256Sha256 házirendet használta.
Az aláíráshoz és a titkosításhoz minden alkalmazásnak saját tanúsítványa van. A kliens és a szerver ellenőrzi egymás tanúsítványát, és elutasítja a kapcsolatot azokkal, akikben nem bízik. Az OPC Foundation .NET-es könyvtárával készített szerver alapértelmezés szerint nem kínálja a titkosítás nélküli None házirendet4.
Az első csatlakozás BadCertificateUntrusted hibával állt le
Az első futtatáskor a kliens nem bízott meg a szerver tanúsítványában, ezért a kapcsolatot elutasította. A kimenet egy része:
fail: Opc.Ua.CertificateValidationCore[91]
Certificate [Subject=CN=DemoPlcServer, CN=urn:komurasoft:demo-plc, Thumbprint=4E236DDA629FE2AB32D185BF681609FD6C525363, NotBefore=2026-11-01, NotAfter=2027-11-01, KeyAlgorithm=1.2.840.113549.1.1.1] validation failed with suppressible errors but was rejected. Reason=Id: BadCertificateUntrusted
...
OPC UA エラー BadCertificateUntrusted [0x801A0000]: [801A0000] (BadCertificateUntrusted) 'Could not verify security on OpenSecureChannel response.'
Ez a könyvtár az elutasított tanúsítványokat a rejected tárolóba menti. Ha a rendszergazda onnan áthelyezi őket a trusted tárolóba, a könyvtár megbízik az adott félben17. Ezúttal a pki/rejected/certs mappában lévő szervertanúsítványt áthelyeztem a pki/trusted/certs mappába, újra lefuttattam a programot, és sikerült csatlakozni. Az áthelyezés előtt egyeztesse a szerver rendszergazdájával a fájlnévben is szereplő ujjlenyomatot4.
flowchart TB
accTitle: A tanúsítvány megbízhatóvá tételének lépései
accDescr: Az ábra azt mutatja, hogy az első csatlakozáskor a kliens elutasítja a szerver tanúsítványát, és a rejected tárolóba menti, majd az ujjlenyomat egyeztetése és a trusted tárolóba helyezés után a következő csatlakozáskor már megbízik benne, és a csatlakozás sikerül.
A["Első csatlakozás"] --> B["BadCertificateUntrusted"]
B --> C["A tanúsítvány a rejected tárolóba kerül"]
C --> D["Az ujjlenyomat egyeztetése a szerver rendszergazdájával"]
D --> E["Áthelyezés a trusted tárolóba"]
E --> F["A következő csatlakozás megbízhatóként sikerül"]
8. ábra: Az elutasított tanúsítvány ellenőrzése és a trusted tárolóba helyezése után a kliens megbízik az adott félben.
Létezik egy AutoAcceptUntrustedCertificates nevű beállítás is, amely automatikusan elfogadja a nem megbízható tanúsítványokat. Az alapértelmezés false, és a könyvtár dokumentációja szerint fejlesztői környezetben hasznos, éles környezetben azonban nem szabad használni17.
A naplóban szereplő NotAfter=2027-11-01 a szimulált szerver tanúsítványának lejárati dátuma. Ez egy asyncua-függvénnyel készített önaláírt tanúsítvány, amely a létrehozása után egy évvel jár le. A berendezések tanúsítványainak is van lejárati idejük, ezért az üzemeltetés részeként előre meg kell határozni, hogyan cseréljük le őket a lejárat előtt, és hogyan tesszük az újakat megbízhatóvá a másik fél számára. A Windows tanúsítványtárolójának kezeléséről a „The Windows Certificate Store in Practice” című cikkben írtam.
A felhasználók hitelesítése
A tanúsítványok az alkalmazásokat ellenőrzik egymás között. Ettől függetlenül a munkamenet megnyitásakor a felhasználót azonosító tokent is átadunk. A specifikáció négyféle tokent határoz meg: névtelen, felhasználónév és jelszó, X.509-tanúsítvány, valamint külső fél által kiadott token18. Az itt bemutatott kliens névtelenül csatlakozott. Azt, hogy a szerver milyen tokeneket fogad el, a szerver végpontadatai tartalmazzák19.
Ahol a helyszíni adatgyűjtés elakad
A következőkben a berendezésadatokat gyűjtő rendszerekben gyakran előforduló problémákat sorolom fel, a mostani kísérlet és a specifikáció alapján.
A szerver leállása alatti értékek nem érkeznek meg
Az előfizetés közben leállítottam a szervert, majd körülbelül 15 másodperc múlva újraindítottam. Ennek a könyvtárnak a ManagedSession osztálya a kapcsolat megszakadásakor automatikusan újracsatlakozik20. Amíg a szerver le volt állítva, a kliens folyamatosan próbált újracsatlakozni.
warn: Opc.Ua.ChannelManager[6]
Reconnect failed. Endpoint=opc.tcp://localhost:4840/demo/, Attempt=3, Outcome=transient-failure, Status=BadNotConnected, ErrorMessage=Could not connect to the remote endpoint.
Amikor a szerver visszatért, az értesítések is újra megérkeztek. Az előfizetés kimenetének egy része:
13:41:13.364 Line1.Temperature 25.61 Good [0x00000000]
13:41:13.865 Line1.Temperature 25.12 Good [0x00000000]
13:41:34.285 Line1.Temperature 26.55 Good [0x00000000]
13:41:33.784 Line1.PartCount 2 Good [0x00000000]
13:41:34.786 Line1.Temperature 26.16 Good [0x00000000]
A 13:41:13 és 13:41:34 közötti időszakból egyetlen érték sem érkezett meg. A darabszám 78-ról 2-re esett vissza. Ennek az az oka, hogy a szimulált szerver újraindításakor a számlálás 0-ról indult újra.
Ebben a példában maga a szerver állt le, így az ez alatti értékek sehol sem maradtak meg. Az újracsatlakozási mechanizmus helyreállítja a kapcsolatot, de utólag nem pótolja a leállás alatti értékeket.
Más a helyzet, ha csak a kommunikáció szakad meg, és a szerver tovább fut. A specifikációban szerepel a Republish szolgáltatás, amellyel a szerver újraküldési sorából ismét el lehet kérni a meg nem érkezett értesítési üzeneteket21. A MonitoredItem várakozási sorában is felgyűlnek az értesítések, de a sor méretét meghaladó rész eldobásra kerül13. Ezt az esetet a mostani kísérletben nem próbáltam ki. Mindkét esetben rögzítse a kapcsolat megszakadásának és helyreállásának időpontját, hogy utólag kiderüljön, melyik időszakban nem érkeztek értékek. A soros kommunikációt használó berendezések újracsatlakozásáról és naplózásának tervezéséről a „Serial Communication App Pitfalls” című cikk is szól.
flowchart TB
accTitle: Rögzítés a szerver leállásakor
accDescr: Az ábra azt mutatja, hogy ha előfizetés közben leáll a szerver, a kliens folyamatosan próbál újracsatlakozni, a szerver visszatérésekor az értesítések is újra megérkeznek, a leállás alatti értékek azonban nem érkeznek meg, ezért a megszakadás és az újracsatlakozás időpontját rögzíteni kell.
A["Előfizetés folyamatban"] --> B["A szerver leáll"]
B --> C["A kliens folyamatosan próbál újracsatlakozni"]
C --> D["A szerver visszatér, az értesítések újraindulnak"]
B -.-> E["A leállás alatti értékek nem érkeznek meg"]
E -.-> F["A megszakadás és az újracsatlakozás időpontjának rögzítése"]
9. ábra: Az újracsatlakozás helyreállítja a kapcsolatot, de a szerver leállása alatti értékek nem érkeznek meg.
Melyik időbélyeget rögzítsük?
A specifikáció szerint a SourceTimestamp az az időpont, amelyet az adat forrása rendelt az értékhez, és annak az időpontnak kell lennie, amikor az érték megváltozott. A ServerTimestamp az az időpont, amikor a szerver megkapta az értéket, vagy amikor kiderült, hogy az érték helyes9. A mostani szimulált szerver maga állítja elő az értékeket, ezért a két időpont megegyezett.
Ha azt szeretné tudni, mikor változott meg egy érték a berendezésen, a SourceTimestamp értéket használja. Ezt az időpontot azonban a forrás órája adja, így ha a berendezés vagy a szerver órája eltér, a rögzített adat is eltér. Ha a gyűjtött adatokat más nyilvántartásokkal vetné össze, mentse el mellettük a fogadó számítógép idejét is, így később ellenőrizhető az eltérés. A Windows oldali időszinkronizálásról a „Windows Time Synchronization (w32time) and Business Systems” című cikkben írtam.
A nem Good állapotú értékeket ne kezelje egyszerű számként
Ha az állapotkód Bad, az értéket figyelmen kívül kell hagyni9. Uncertain állapot esetén az érték egyes célokra nem használható10. Mielőtt az értékek grafikonokba vagy összesítésekbe kerülnének, válogassa szét őket állapotkód szerint, és határozza meg, mi történjen a nem Good állapotú értékekkel. A várakozási sor megtelését jelző Overflow bit is az állapotkódban áll be13. A berendezések állapotának képernyőn való megjelenítéséről a „Best Practices for Checking and Displaying External Device State” című cikk szól.
Nyissa meg a portot a tűzfalon
Az IANA-nál nyilvántartott OPC UA-port a 4840/TCP3. Nem minden szerver használja azonban ezt a számot. Az OPC Foundation .NET-es mintái például a 62541-es portot is használják4. Ellenőrizze a portszámot a berendezés végpontjának URL-jében, és engedélyezze az erre a portra irányuló kapcsolatokat. Ha a szerver Windowson fut, annak a gépnek a Windows tűzfalában, ha pedig hálózati eszköz van közöttük, azon az eszközön engedélyezze. A bejövő szabályok létrehozásáról a „The Windows Firewall and Business Applications” című cikkben írtam.
flowchart TB
accTitle: Ahol az adatgyűjtés elakad
accDescr: Az ábra a berendezésadatok gyűjtésének buktatóit mutatja két csoportra osztva: a rögzített adatok tartalma (a szerver leállása alatti értékek nem érkeznek meg, melyik időbélyeget rögzítsük, a nem Good állapotú értékek kezelése) és a csatlakozás előkészítése (tűzfalportok, a tanúsítványok lejárata).
A["Ahol az adatgyűjtés elakad"] --> R["A rögzített adatok tartalma"]
A --> N["A csatlakozás előkészítése"]
R --> B["A leállás alatti értékek nem érkeznek meg"]
B ~~~ C["Melyik időbélyeg"]
C ~~~ D["A nem Good értékek kezelése"]
N --> E["Tűzfalportok"]
E ~~~ F["A tanúsítványok lejárata"]
10. ábra: A sikeres csatlakozás után is ellenőrizze a hiányzó adatokat, az időpontokat, az állapotot, a portokat és a tanúsítványokat.
Választás az OPC UA, a Modbus/TCP és a gyártók saját kommunikációja között
A PLC-kkel és berendezésekkel való kommunikációra az OPC UA mellett a Modbus/TCP és a PLC-gyártók által biztosított kommunikáció is rendelkezésre áll.
A Modbus specifikációja négy táblában kezeli az adatokat: a csak olvasható, 1 bites Discrete Input, az írható-olvasható, 1 bites Coil, a csak olvasható, 16 bites Input Register és az írható-olvasható, 16 bites Holding Register táblában22. Az IANA a Modbus alkalmazásprotokollja (mbap) számára az 502/TCP portot tartja nyilván3.
Ezekbe a táblákba bitek és 16 bites szavak kerülnek, ezért azt, hogy melyik címen milyen érték milyen formátumban található, a berendezés dokumentációjában kell ellenőrizni, és a kliens oldalán kell leírni. Az OPC UA-ban, ahogy eddig láttuk, a szerver névvel ellátott változókat tesz közzé a címtérben, a kliens pedig a Browse segítségével fel tudja deríteni őket. Az értékekhez állapotkód és időbélyeg tartozik, a csatlakozást pedig tanúsítvány engedélyezi.
Hogy melyiket használjuk, azt sokszor az dönti el, mit biztosít a berendezés. Ha a berendezésnek van OPC UA-szervere, azt használjuk; ha csak Modbus/TCP-t támogat, címtérképet készítünk, és az alapján olvasunk. Ha csak a gyártó saját kommunikációja vagy SDK-ja áll rendelkezésre, annak dokumentációját követjük. Az USB-eszközökkel való kommunikáció módjának kiválasztásáról a „How to Work with USB Devices from a Windows App” című cikkben írtam.
flowchart TB
accTitle: A berendezéssel való kommunikáció módjának kiválasztása
accDescr: Az ábra azt mutatja, hogy ha a berendezésnek van OPC UA-szervere, OPC UA-val böngésszük és gyűjtjük a változókat, ha csak Modbus/TCP-t támogat, a dokumentációban ellenőrizzük a címeket és a formátumokat, és regisztereket olvasunk, ha pedig csak a gyártó saját kommunikációja áll rendelkezésre, annak dokumentációját követjük.
A["A berendezés által biztosított kommunikáció"] --> B{"Mi áll rendelkezésre?"}
B -->|"OPC UA-szerver"| C["A változók böngészése és gyűjtése"]
B -->|"Csak Modbus/TCP"| D["A címek és formátumok ellenőrzése a dokumentációban"]
B -->|"Csak gyártói kommunikáció"| E["A gyártó dokumentációjának és SDK-jának követése"]
D --> F["A regiszterek kiolvasása és értékké alakítása"]
11. ábra: Hogy mivel gyűjtjük az adatokat, azt sokszor az dönti el, mit biztosít a berendezés.
Kapcsolódó cikkek
- Dropped Frames with GigE Vision and USB3 Vision Cameras — Locating the Cause and the Windows Settings to Review
- Serial Communication App Pitfalls - Through Reconnection and Log Design
- Best Practices for Checking and Displaying External Device State
- How to Work with USB Devices from a Windows App
- The Windows Firewall and Business Applications
- The Windows Certificate Store in Practice
- Windows Time Synchronization (w32time) and Business Systems
Források
-
OPC Foundation, Classic. Hogy az OPC Classic a COM/DCOM-on alapul, a DA, A&E és HDA specifikációk, az OPC UA 2008-as közzététele és az újratervezés okai. ↩ ↩2
-
IEC, IEC TR 62541-1:2020 OPC Unified Architecture - Part 1: Overview and concepts. Az IEC 62541 sorozat 1. része, amely az OPC UA fogalmait és áttekintését tárgyalja (azóta újabb kiadás váltotta fel). ↩
-
IANA, Service Name and Transport Protocol Port Number Registry. Az
opcua-tcp(4840/TCP) és azmbap(502/TCP) nyilvántartása. ↩ ↩2 ↩3 -
OPC Foundation, UA-.NETStandard 2.0.1: Getting started. A 2.0-s sorozatú kliens megírásának módja, hogy a
ReadValueAsyncBad állapotnál kivételt dob, az elutasított és a megbízható tanúsítványok tárolói, hogy a szerverek alapértelmezés szerint nem kínálják aNoneházirendet, valamint a mintákban használt portszámok. ↩ ↩2 ↩3 ↩4 ↩5 -
FreeOpcUa, asyncua (PyPI). A szimulált berendezésszerverhez használt Python OPC UA-könyvtár. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 5.9.2 Browse. A csomópontok hivatkozásait követő szolgáltatás. ↩
-
OPC Foundation, OPC 10000-3 v1.05, 8.2.2 NamespaceIndex. Hogy a szolgáltatásokon belül a névtér URI-ját szám jelöli, és ez a szám a NamespaceArray egy pozíciójának felel meg. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 5.11 Attribute Service Set. A Read és a Write szolgáltatás. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 7.11 DataValue. Az érték, az állapotkód, a SourceTimestamp és a ServerTimestamp meghatározása. ↩ ↩2 ↩3
-
OPC Foundation, OPC 10000-4 v1.05, 7.38.1 StatusCode General. A felső két bit által jelzett Good, Uncertain és Bad állapot. ↩ ↩2
-
OPC Foundation, OPC 10000-4 v1.05, 5.13.1.2 Sampling interval. Hogy a mintavételi időköz „best effort” ciklus. ↩ ↩2
-
OPC Foundation, OPC 10000-4 v1.05, 7.22.2 DataChangeFilter. Hogy szűrő nélkül az érték vagy az állapot változásakor jön értesítés. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 5.13.1.5 Queue parameters. A várakozási sor mérete, az eldobás módja és az Overflow bit. ↩ ↩2 ↩3
-
OPC Foundation, OPC 10000-4 v1.05, 5.14.1.1 Subscription model. A közzétételi időköz és a keep-alive. ↩
-
OPC Foundation, UA-.NETStandard 2.0.1: Subscriptions and Monitored Items Service Set. A
SubscribeDataChangesAsync, valamint aMonitoredItemOptionsmintavételi időköze és sormérete. ↩ -
OPC Foundation, OPC 10000-4 v1.05, 7.20 MessageSecurityMode. A None, a Sign és a SignAndEncrypt jelentése. ↩
-
OPC Foundation, UA-.NETStandard 2.0.1: Certificates. Az a gyakorlat, hogy a tanúsítványokat a rejected tárolóból a megbízható tárolóba helyezzük át, valamint hogy az
AutoAcceptUntrustedCertificatesbeállítást éles környezetben nem szabad használni. ↩ ↩2 -
OPC Foundation, OPC 10000-4 v1.05, 7.40 UserIdentityToken parameters. A négyféle token: névtelen, felhasználónév, X.509 és kiadott token. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 7.14 EndpointDescription. A végpont által elfogadott felhasználói tokenek listája (userIdentityTokens). ↩
-
OPC Foundation, UA-.NETStandard 2.0.1: Sessions, Reconnection, and Subscription Engines. Hogy a
ManagedSessionbeépített újracsatlakozási mechanizmussal rendelkezik. ↩ -
OPC Foundation, OPC 10000-4 v1.05, 5.14.6.1 Republish. Az a szolgáltatás, amellyel az előfizetés újraküldési sorából ismét el lehet kérni az értesítési üzeneteket. ↩
-
Modbus-IDA, MODBUS Application Protocol Specification V1.1b (a Chicagói Egyetem szerverén tárolt másolat). A 4.3. szakasz adatmodellje (Discrete Input, Coil, Input Register, Holding Register). ↩
Kapcsolódó cikkek
Azonos címkéket használó, legfrissebb cikkek. Mélyítse el ismereteit szorosan kapcsolódó témákban.
Mi áll le, ha bekapcsolja a „forgalmi díjas kapcsolat” beállítást? – Hatás a Windows Update-re, a OneDrive-ra és az áruházbeli alkalmazásokra
Forgalmi díjas kapcsolaton a Windows Update csak a kiemelt frissítéseket tölti le, a OneDrive szünetelteti a szinkronizálást. Áruház, beá...
Törölhető-e a Windows.old és az „Ideiglenes fájlok”? ── Mikor a Tárolási segéd, és mikor a Lemezkarbantartó
A Windows.old és az ideiglenes fájlok törléséről az dönt, hogy elveszít-e közben valamit, amit utána nem kaphat vissza. A cikk a Microsof...
Mit változtat a Windows energiagazdálkodási módja? ── A legjobb teljesítmény, a kiegyensúlyozott és a legjobb energiahatékonyság különbsége, és hogyan válasszon
Mit változtatnak a Windows 11 energiagazdálkodási módjai (Legjobb teljesítmény, Kiegyensúlyozott, Legjobb energiahatékonyság): a háttérbe...
Mi a Windows Játékmód? ── Mi változik, ha bekapcsolja, és hat-e a játékokon kívül másra is?
A Windows Játékmód játék közben leállítja a Windows Update illesztőprogram-telepítéseit és újraindítási értesítéseit, hogy stabilabb legy...
Mi a „Dedikált GPU-memória” és a „Megosztott GPU-memória” a Feladatkezelőben? ── Miért térnek el ennyire a számok az integrált GPU-knál, és mi történik, ha kevés a memória
Közérthetően elmagyarázzuk, mit jelent a Feladatkezelőben a dedikált és a megosztott GPU-memória: miért kicsi a dedikált és nagy a megosz...
Kapcsolódó témák
Ehhez a témához közel álló témaoldalak. A cikkből kiindulva eljuthat a kapcsolódó szolgáltatásokhoz és további cikkekhez.
Windows-technológiai témák
Áttekintő oldal a Windows-fejlesztés, a hibakeresés és a meglévő megoldások továbbhasznosítása műszaki témáihoz.
Mely szolgáltatásokhoz kapcsolódik ez a téma
Ez a cikk a következő szolgáltatási oldalakhoz kapcsolódik. Kezdje azzal, amelyik a leginkább illik az Ön helyzetéhez.
Windows-alkalmazások fejlesztése
Egy olyan Windows-alkalmazás elkészítése, amely berendezésekből gyűjt adatokat – az előfizetés beállításával, az újracsatlakozással, valamint az időbélyegek és az állapot rögzítésével együtt –, Windows-alkalmazásfejlesztésként vállalható.
Műszaki tanácsadás és tervezési felülvizsgálat
Ha el szeretné dönteni, hogy OPC UA-val gyűjtsön-e adatokat, vagy Modbus/TCP-t, illetve a gyártó saját kommunikációját használja, és hogyan kezelje a tanúsítványokat, ezt technikai konzultációként és tervezési felülvizsgálatként vállaljuk.
Gyakori kérdések
A cikk témájával kapcsolatban a konzultációk során gyakran felmerülő kérdések.
- Mi a különbség az OPC UA és az OPC Classic (OPC DA) között?
- Az OPC Classic olyan specifikáció, amely a Windows COM/DCOM technológiáján keresztül cserél adatokat. Az OPC UA egy 2008-ban közzétett, adott operációs rendszertől független specifikáció, amely egységesen kezeli a Classic funkcióit. Az OPC UA-kliensek Windowson kívül is futnak, és nincs szükség DCOM-beállításra.
- Ha OPC UA-val gyűjtök értékeket, elég rendszeres időközönként kiolvasni őket?
- Ha kevés értékről van szó, és hosszú az időköz, olvasással is gyűjthetők. Ha az értékek változását akarja követni, előfizetéssel a szerverre bízhatja a mintavételt, és értesítést kérhet a változásokról. Mindkét esetben rögzítse az értékkel együtt visszaadott állapotkódot és időbélyegeket is.
- Miért kapok BadCertificateUntrusted hibát csatlakozáskor?
- Azért, mert a kliens még nem bízik meg a szerver tanúsítványában. Az OPC Foundation .NET-es könyvtára az elutasított tanúsítványokat a rejected tárolóba menti. Egyeztesse a tanúsítvány ujjlenyomatát a szerver rendszergazdájával, majd helyezze át a trusted tárolóba. A tanúsítványokat automatikusan elfogadó beállítást csak fejlesztői környezetben használja.
- Milyen portszámot használ az OPC UA?
- Az IANA a 4840/TCP portot opcua-tcp néven tartja nyilván. A valódi szerverek azonban más portot is használhatnak, ezért ellenőrizze a berendezés beállításaiban. Ha a szerver Windowson fut, a Windows tűzfalban, ha pedig hálózati eszköz van közöttük, azon az eszközön kell engedélyezni az adott portra irányuló forgalmat.
A szerző bemutatása
A cikk szerzőjének bemutatkozó oldala.
Go Komura
A KomuraSoft LLC képviselője
Fő területei a Windows-szoftverfejlesztés, a műszaki konzultáció és a hibakeresés; különösen a meglévő megoldásokat érintő projektekben, valamint a nehezen felderíthető okú hibák kivizsgálásában erős.