通过 Utgard 连接到 Matrikon OPC 模拟服务器

Connection to Matrikon OPC Simulation Server via Utgard

我正在使用 Matrikon OPC 服务器进行模拟和测试,而不是 TOPServer,以及教程 HowToStartWithUtgard。我无法连接到服务器。这是我得到的错误:

    15:02:18.452 [main] DEBUG o.j.dcom.transport.JIComTransport - Socket closed... Socket[unconnected] host XXX.XXX.XX.X, port 135
15:02:18.453 [main] WARN  org.jinterop.dcom.core.JIComServer - Got the class not registered exception , will attempt setting entries based on status flags...
15:02:18.468 [main] INFO  org.openscada.opc.lib.da.Server - Failed to connect to server
org.jinterop.dcom.common.JIException: Class not registered. If you are using a DLL/OCX , please make sure it has "DllSurrogate" flag set. Faq A(6) in readme.html. [0x80040154]
    at org.jinterop.dcom.core.JIComServer.init(Unknown Source) ~[org.openscada.jinterop.core_2.0.8.201303051454.jar:na]
    at org.jinterop.dcom.core.JIComServer.initialise(Unknown Source) ~[org.openscada.jinterop.core_2.0.8.201303051454.jar:na]
    at org.jinterop.dcom.core.JIComServer.<init>(Unknown Source) ~[org.openscada.jinterop.core_2.0.8.201303051454.jar:na]
    at org.openscada.opc.lib.da.Server.connect(Server.java:117) ~[org.openscada.opc.lib_1.0.0.201303051455.jar:na]
    at com.matrikonopc.utgard.tutorial.UtgardReadTutorial.main(UtgardReadTutorial.java:31) [bin/:na]
Caused by: org.jinterop.dcom.common.JIRuntimeException: Class not registered. If you are using a DLL/OCX , please make sure it has "DllSurrogate" flag set. Faq A(6) in readme.html. [0x80040154]
    at org.jinterop.dcom.core.JIRemActivation.read(Unknown Source) ~[org.openscada.jinterop.core_2.0.8.201303051454.jar:na]
    at ndr.NdrObject.decode(Unknown Source) ~[org.openscada.jinterop.deps_1.0.0.201303051454.jar:na]
    at rpc.ConnectionOrientedEndpoint.call(Unknown Source) ~[org.openscada.jinterop.deps_1.0.0.201303051454.jar:na]
    at rpc.Stub.call(Unknown Source) ~[org.openscada.jinterop.deps_1.0.0.201303051454.jar:na]
    ... 5 common frames omitted
15:02:18.469 [main] INFO  org.openscada.opc.lib.da.Server - Destroying DCOM session...
15:02:18.470 [main] INFO  org.openscada.opc.lib.da.Server - Destroying DCOM session... forked
80040154: Unknown error (80040154)
15:02:18.499 [OPCSessionDestructor] DEBUG org.openscada.opc.lib.da.Server - Starting destruction of DCOM session
15:02:18.500 [OPCSessionDestructor] INFO  org.jinterop.dcom.core.JISession - About to destroy 0 sessesion which are linked to this session: 1325311425
15:02:18.500 [OPCSessionDestructor] INFO  o.j.dcom.core.JIComOxidRuntime - destroySessionOIDs for session: 1325311425
15:02:18.500 [OPCSessionDestructor] INFO  org.openscada.opc.lib.da.Server - Destructed DCOM session
15:02:18.501 [OPCSessionDestructor] INFO  org.openscada.opc.lib.da.Server - Session destruction took 27 ms

I do not know where I should register the Class and what Class it refers to.

它指的是您尝试使用的 clsid -- 它不在注册表中。您能否再次检查您使用的 Matrikon OPC 模拟服务器是否正确?

工作演示,在 Windows 10 和 Java 8 上测试。

用户必须在 Windows 上具有管理员权限。

可能出现的错误:

00000005:登录错误(用户是否有管理员权限!?)
8001FFFF: 防火墙、RPC 动态端口未打开(见下文)
80040154:仔细检查注册表中的 CLSID,低于 HKEY_CLASSES_ROOT

防火墙规则

netsh advfirewall firewall add rule^
  name="DCOM-dynamic"^
  dir=in^
  action=allow^
  protocol=TCP^
  localport=RPC^
  remoteport=49152-65535

rem the next one does not seems needed
netsh advfirewall firewall add rule name="DCOM" dir=in action=allow protocol=TCP localport=135

Java代码

package demo.opc;

import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.openscada.opc.lib.common.ConnectionInformation;
import org.openscada.opc.lib.da.AccessBase;
import org.openscada.opc.lib.da.DataCallback;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.ItemState;
import org.openscada.opc.lib.da.Server;
import org.openscada.opc.lib.da.SyncAccess;

public class UtgardReaderDemo {
  /**
   * Main application, arguments are provided as system properties, e.g.<br>
   * java -Dhost="localhost" -Duser="admin" -Dpassword="secret" -jar demo.opc.jar<br>
   * Tested with a windows user having administrator rights<br>
   * @param args unused
   * @throws Exception in case of unexpected error
   */
  public static void main(String[] args) throws Exception {
    Logger.getLogger("org.jinterop").setLevel(Level.ALL); // Quiet => Level.OFF

    final String host = System.getProperty("host", "localhost");
    final String user = System.getProperty("user", System.getProperty("user.name"));
    final String password = System.getProperty("password");
    // Powershell: Get-ItemPropertyValue 'Registry::HKCR\Matrikon.OPC.Simulation.1\CLSID' '(default)'
    final String clsId = System.getProperty("clsId", "F8582CF2-88FB-11D0-B850-00C0F0104305");
    final String itemId = System.getProperty("itemId", "Saw-toothed Waves.Int2");

    final ConnectionInformation ci = new ConnectionInformation(user, password);
    ci.setHost(host);
    ci.setClsid(clsId);

    final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
    server.connect();

    final AccessBase access = new SyncAccess(server, 1000);
    access.addItem(itemId, new DataCallback() {
      public void changed(final Item item, final ItemState state) {
        System.out.println(state);
      }
    });

    access.bind();
    Thread.sleep(10_000L);
    access.unbind();
  }
}

build.gradle

plugins {
  id 'java-library'
  id 'eclipse'
}

repositories {
  mavenCentral()
}

dependencies {
  implementation 'org.bouncycastle:bcprov-jdk15on:1.60'
  implementation 'org.openscada.utgard:org.openscada.opc.lib:1.5.0'
}

jar  {
  manifest {
    attributes(
      'Class-Path': configurations.runtimeClasspath.collect { 'lib/' + it.getName() }.join(' '),
      'Main-Class': 'demo.opc.UtgardReaderDemo'
    )
  }
}

assemble {
  dependsOn 'dependenciesCopy'
}

task dependenciesCopy(type: Copy) {
  group 'dependencies'
  from sourceSets.main.compileClasspath
  into "$libsDir/lib"
}