JAVA实现OPC DA遇到的常见问题及解决方法 您所在的位置:网站首页 star–561连接 JAVA实现OPC DA遇到的常见问题及解决方法

JAVA实现OPC DA遇到的常见问题及解决方法

2024-06-02 21:53| 来源: 网络整理| 查看: 265

前言

由于工作对接工业协议比较多,平时采集少量数据都是采用的modbus协议,但是最近要采集大量数据,modbus就不适用了,所以采用opc形式。期间遇到0x00000005,0x80070005,0x80040153,0x80010111等问题,避免大家踩坑,记录一下解决方法。

为什么使用OPC DA

虽然OPC DA从1.0,2.0到3.0经历过几次更新,由于其复杂的环境配置和win的局限性,da的形式也逐渐不建议使用,推出了更加简单方便跨平台的OPC UA,但是老旧的控制系统依然只支持DA这种形式,所以为了兼容过去的DCS,PLC等系统必须支持OPC DA的读写方式。

关于OPC UA

如果可以使用UA尽量不要使用DA,推荐Eclipse的milo开源库,后面我会单独出一期聊聊UA相关。

实现方式

查找了好久java的OPC DA开源库只有Utgard和Jeasyopc两种

UtgardJeasyopcLinux支持(纯Java编写)不支持       Windows64支持(纯Java编写)不支持用户名密码需要不需要组查询不支持支持压力测试(单线程同步)略快7W点大约在4224ms略慢7W点大约在22540msDCOM通过DCOM实现,必须配置不需要配置现状 作者删库跑路只支持 IA 32,不支持AMD 64

其中Jeasyopc是通过调用JCustomOpc.dll,需要配置JCustomOpc.dll文件,而且支持只32位系统。所以选用了Utgard来实现。

OPC Server模拟

参考这位大佬:OPCServer:使用KEPServer - ioufev - 博客园

DCOM配置

还是参考这位大佬:OPC和DCOM配置 - ioufev - 博客园

Maven依赖 org.jinterop j-interop 3.0.0

这是Utgard调用的类库,不过Utgard引用的是2.0.4版本,一定要更换成3.0.0版本,否则会有可能碰到0x80010111错误。

Utgard的类库不建议通过maven坐标方式引入,因为其中有很多bug我们需要做一些简单的修改,建议下载源码,修改完成后通过jar方式引入maven,或者直接复制到项目下。

代码实现

具体读写代码我这里就不贴了,可以参考一下上面那位大佬:Java OPC 代码 - ioufev - 博客园

我这里做一下补充

首先是获取主机上的所有OPC Server列表,可以直接获取ClsId和ProgId等信息

ServerList serverList = new ServerList(HOST,USERNAME, PASSWORD,DOMAIN); Collection detailsList = serverList.listServersWithDetails(new Category[] {Categories.OPCDAServer10, Categories.OPCDAServer20 ,Categories.OPCDAServer30}, new Category[] {}); for (final ClassDetails details : detailsList) { log.info("ClsId=" + details.getClsId() + " ProgId=" + details.getProgId() + " Description=" + details.getDescription()); }

上文提到的大佬读取数据可以用下面这段进行解析,省的大家再去debug返回的对象结构

private static Object getVal(JIVariant var) throws JIException { Object value; int type = var.getType(); switch (type) { case JIVariant.VT_I2: value = var.getObjectAsShort(); break; case JIVariant.VT_I4: value = var.getObjectAsInt(); break; case JIVariant.VT_I8: value = var.getObjectAsLong(); break; case JIVariant.VT_R4: value = var.getObjectAsFloat(); break; case JIVariant.VT_R8: value = var.getObjectAsDouble(); break; case JIVariant.VT_BSTR: value = var.getObjectAsString2(); break; case JIVariant.VT_BOOL: value = var.getObjectAsBoolean(); break; case JIVariant.VT_UI2: case JIVariant.VT_UI4: value = var.getObjectAsUnsigned().getValue(); break; case JIVariant.VT_EMPTY: throw new JIException(JIErrorCodes.JI_VARIANT_IS_NULL, "Variant is Empty."); case JIVariant.VT_NULL: throw new JIException(JIErrorCodes.JI_VARIANT_IS_NULL, "Variant is null."); default: throw new JIException(JIErrorCodes.JI_VARIANT_IS_NULL, "Unknown Type."); } return value; }

获取服务器下所有ITEM列表

Collection items = server.getFlatBrowser().browse(); 遇到的问题 0x00000005

原因:用户校验不通过。

解决方法:检查用户名和密码,用户名不要使用全名

如果用户名和密码没有问题,那么就有可能是本地安全策略的问题,可以通过下面方法解决。

1、win+r运行  secpol.msc 

2、找到本地策略 - 安全选项 - 网络访问:本地账户的共享和安全模型

 3、修改属性为“经典:对本地账户进行身份验证,不改变其本来身份”

0x8001FFFF

解决方法:检查dcom配置是否正确,防火墙设置是否正确,按照上面大佬的步骤一步一步重新配置一下。

0x80070005

解决方法:这个就是上文提到的不建议maven方式直接引入Utgard,需要修改 org.openscada.opc.lib.da包下的Server.class,开启会话安全项,再原来connect()方法添加两处this.session.useSessionSecurity(true);

而且Utgard的通过ProgId建立连接也有问题,具体为什么获取不到连接我没仔细查找,不过也可以在这个地方做修改实现通过ProgID建立连接。

修改完成如下

public synchronized void connect() throws IllegalArgumentException, UnknownHostException, JIException, AlreadyConnectedException { if (isConnected()) { throw new AlreadyConnectedException(); } final int socketTimeout = Integer.getInteger("rpc.socketTimeout", 0); log.debug(String.format("Socket timeout: %s ", socketTimeout)); try { if (this.connectionInformation.getClsid() != null) { this.session = JISession.createSession( this.connectionInformation.getDomain(), this.connectionInformation.getUser(), this.connectionInformation.getPassword()); this.session.setGlobalSocketTimeout(socketTimeout); this.session.useSessionSecurity(true); this.comServer = new JIComServer( JIClsid.valueOf(this.connectionInformation.getClsid()), this.connectionInformation.getHost(), this.session); } else if (this.connectionInformation.getProgId() != null) { this.session = JISession.createSession( this.connectionInformation.getDomain(), this.connectionInformation.getUser(), this.connectionInformation.getPassword()); this.session.setGlobalSocketTimeout(socketTimeout); ServerList serverList = new ServerList(this.connectionInformation.getHost(), this.connectionInformation.getUser(), this.connectionInformation.getPassword(), this.connectionInformation.getDomain()); String clsIdFromProgId = serverList.getClsIdFromProgId(this.connectionInformation.getProgId()); // this.comServer = new JIComServer(JIProgId.valueOf(this.connectionInformation.getProgId()),this.connectionInformation.getHost(), this.session); this.comServer = new JIComServer( JIClsid.valueOf(clsIdFromProgId), this.connectionInformation.getHost(), this.session); } else { throw new IllegalArgumentException("Neither clsid nor progid is valid!"); } this.server = new OPCServer(this.comServer.createInstance()); this.errorMessageResolver = new ErrorMessageResolver( this.server.getCommon(), this.defaultLocaleID); } catch (final UnknownHostException e) { log.error("Unknown host when connecting to server", e); cleanup(); throw e; } catch (final JIException e) { log.error("Failed to connect to server", e); cleanup(); throw e; } catch (final Throwable e) { log.error("Unknown error", e); cleanup(); throw new RuntimeException(e); } notifyConnectionStateChange(true); } 0x80040154

原因:ClsId不正确

解决方法:检查OPCServer的ClsId,或者通过上文提到的获取OPC Server列表的方式获取ClsId

0x80040153

原因:系统中有过OPCServer的注册表没有删除干净,所以通过ClsId找不到OPCServer

解决方法:这个问题困扰了我很长时间,因为注册表实在太多,没法找到并删除,而电脑里有很多东西又不想重做系统。可以通过修改org.openscada.opc.lib.list;包下的 listServersWithDetails(final Category[] implemented, final Category[] required)方法处理该异常

修改完成如下

public Collection listServersWithDetails(final Category[] implemented, final Category[] required) throws IllegalArgumentException, UnknownHostException, JIException { Collection resultString = listServers(implemented, required); List result = new ArrayList(resultString.size()); for (String clsId : resultString) { //TODO 注册表没清理干净会报错 ,只做了异常处理 try { result.add(getDetails(clsId)); }catch (JIException e){ logger.error(clsId+":Message not found for errorCode: 0x80040153"); e.printStackTrace(); } } return result; } 0x80010111

原因:utgard的协议5.6,但windows 10 2004之后的协议都是5.7

解决方法:使用 j-interop 3.0

org.jinterop j-interop 3.0.0

 使用j-interop3.0需要再maven中添加repository如下,否则会报错找不到各种包

clojars Clojars https://repo.clojars.org/ Utgard源码

我自己项目里用的,已经改好了上文提到的部分,直接复制到自己项目里或者打jar就可以使用

链接:https://pan.baidu.com/s/13vcXF74gym-cvhp_myU9rw?pwd=pnjm  提取码:pnjm

J-interop 3.0 jar

链接:https://pan.baidu.com/s/1b49Z8BvL-ADhe2YZPZVoEg?pwd=9fdp  提取码:9fdp 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有