迁移

0.13.1 到 1.0.0

qianmoQqianmoQ· 更新于 2026-10-01· 阅读 21 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

1.0.0 是 Apache PLC4X 的第一个大版本发布,此前不断累积的不兼容变更在这一刻一次性完成,而不是分散到其后的五个版本中。本页介绍的变更无论你使用哪种语言调用 PLC4X 都适用——它们涉及连接串、标签地址和默认值,而不涉及任何一种 API。

API 的变更因语言而异,各自记录在对应的页面中:

请先阅读本页,然后再看你所用语言的页面。大多数升级在连接串和标签地址上花费的时间,远比在 API 上花费的多。

一段话概括

标签地址在所有驱动、所有语言中都使用同一种写法来选择数组元素。每个表示时长的连接串参数都以 -ms 结尾,每项 TLS 设置都位于 tls. 之下,每项传输设置都写在其传输协议的代码之下。驱动会拒绝它不支持的传输方式。OPC UA 与 TLS 传输默认校验证书,这意味着过去那种无保护的连接现在会失败,并给出失败原因。Java 需要 21,Go 需要 1.27。

标签地址:统一的数组写法

这是最可能影响你代码的变更,因为它出现在你的应用传给 addTagAddress(…​) 的字符串中。

数组选择现在写在数据类型之前,单个元素使用 [n],闭区间使用 [lo..hi]:

holding-register:1:INT[4]      (1)
holding-register:1[0..3]:INT   (2)
1之前 —— 四个寄存器的计数
2现在 —— 索引 0 到 3 的元素

这取代了四种互不兼容的写法。[4] 在七种类标签中表示“四个元素”,在两类中表示“第五个元素”;现在它在所有地方都表示一个元素。

旧形式的地址不再能被解析,错误信息会给出应当写入的地址——因此升级会显式报告这一变化,而不是悄悄返回不同的数据。恰好存在三种例外:地址仍然可以解析,只是其含义发生了变化,因此无法给出任何警告:

  • Firmata 地址不携带数据类型(3[4]),所以括号并未移动。3[4] 原先从引脚 3 开始读取四个引脚,现在读取一个引脚,即第五个。请改写为 3[0..3]。
  • PLC4Go 的 ADS 驱动与 PLC4J 的不同,它把 [n] 当作计数使用。MAIN.g_arr[3] 原先读取三个元素,现在读取索引 3 处的元素。请改写为 MAIN.g_arr[0..2]。
  • PLC4Go 的 Firmata 驱动因为与 PLC4J 相同的原因而发生变化。

发生变化的形式,按驱动列出:

驱动0.13.11.0.0
S7%DB42:28.0:BYTE[4]%DB42:28.0[0..3]:BYTE
S7(字符串)%DB1:0:STRING(20)[4]%DB1:0[0..3]:STRING(20)
Modbusholding-register:1:INT[4]holding-register:1[0..3]:INT
SLMPD100:INT[4]D100[0..3]:INT
ADS(直接)0x4020/0:DINT[4]0x4020/0[0..3]:DINT
EtherNet/IPmyArray[0]:DINT:4myArray[0..3]:DINT
Profinettag:INT[4]tag[0..3]:INT
Profinet-NG1.2.INPUT.0:INT[4]1.2.INPUT.0[0..3]:INT
模拟(Simulated)RANDOM/foo:INT[4]RANDOM/foo[0..3]:INT
KNXnet/IP(Go)1.2.3#4B1C:UINT[4]1.2.3#4B1C[0..3]:UINT

OPC UA、C-Bus、BACnet/IP 以及 KNXnet/IP 的组地址保持不变。OPC UA 正是这套共享表示法从中提取的驱动;另外三个则用括号表示并非数组选择的含义。

即使你的地址一个都不变,也有两条规则值得了解:

  • 单个索引与单元素范围不再是同一回事。 myTag[4] 选择一个元素并产生标量,myTag[4..4] 产生一个包含单个元素的列表。
  • 不选择任何内容的地址现在表示取整个值。 对于标量这没有变化;对于数组则表示所有元素——但仅限于能够向设备查询长度的驱动(OPC UA、ADS、UMAS)。

完整语法,包括 PLC 声明数组起点不为零时使用的 ;base 后缀,见 数组寻址 页面。

连接串参数:统一的词汇

参数名称现在在 PLC4J 和 PLC4Go 中拼写一致。以毫秒为单位的时长以 -ms 结尾,TLS 设置位于 tls. 之下,而面向某种传输的参数不再重复该传输的代码,因为前缀已经提供了它。

旧名称是被移除,而非弃用。提供其中任何一个都会被报告为未知参数,并指出替代名称——而且该设置不会生效。

0.13.11.0.0
request-timeoutrequest-timeout-ms
timeout-request (ads)request-timeout-ms
connect-timeoutconnect-timeout-ms
read-timeoutread-timeout-ms
write-timeoutwrite-timeout-ms
session-timeoutsession-timeout-ms
channel-lifetimechannel-lifetime-ms
min-channel-lifetimemin-channel-lifetime-ms
ha-heartbeat-intervalha-heartbeat-interval-ms
ha-failover-timeoutha-failover-timeout-ms

表 1. 持续时间

建立套接字连接与完成协议握手是两个设置,而不是一个,因此现在它们有两个名称。connect-timeout-ms 是套接字连接;COTP 握手和 OPC UA 协商步骤是 handshake-timeout-ms:

0.13.11.0.0
cotp.cotp-connection-timeoutcotp.handshake-timeout-ms
negotiation-timeout (opcua)handshake-timeout-ms
0.13.11.0.0
tcp.tcp-no-delaytcp.no-delay
cotp.cotp-tpdu-sizecotp.tpdu-size
tls.tls-versiontls.version

表 2 传输参数不再重复其传输的代码

0.13.11.0.0
tls.verify-ssltls.verify
key-store-file (opcua)tls.keystore
key-store-passwordtls.keystore-password
key-store-typetls.keystore-type
trust-store-filetls.trust-store
trust-store-passwordtls.trust-store-password
trust-store-typetls.trust-store-type

表 3 TLS 设置归入 tls. 之下

信任库去掉了 -file,原因与密钥库相同:这些名称中的每一个都指明了这是一个库,再说一遍毫无意义。

由协议规范固定的名称保留其原有的拼写和单位。SLMP 的 monitoring-timer 是 3E 请求帧中的一个字段,使用的是协议自身的单位,而不是毫秒,因此保持不变。

OPC UA 驱动上的 insecure-certificate-verification 改为 tls.verify,含义相反。原先设置 insecure-certificate-verification=true 的连接现在必须设置 tls.verify=false。这一项不只是改名:如果漏掉了,就会采用新的默认值,即校验证书服务器。

未知参数现在会被报告

PLC4X 无法识别的参数会按名称报告,如果存在相近的已知名称,也会一并给出,在 PLC4J 和 PLC4Go 中皆是如此。它仍然只是一条警告——多余的参数不会让一个本来能正常工作的连接失败——所以升级后的首次运行是查看日志的好时机。

该报告还知道连接实际使用的是哪一种传输,因此属于另一种传输的参数(在 TCP 连接上的 serial.baud-rate)会被指出为投错地方,而不是被放过。

PLC4Go 的 OPC UA 驱动过去遇到未知选项会拒绝连接。现在它会像其他所有驱动一样发出警告。

驱动会拒绝它不支持的传输

将驱动与它不讲的传输配对——例如把 S7 驱动(讲 COTP)与普通的 tcp 传输配对——现在会在连接时失败,并抛出一个异常,指明该驱动支持哪些传输。此前它会先连上,再以一种难懂得多的方式失败。

如果这种非标准配对是有意为之,请设置 allow-unsupported-transport=true。这只绕过驱动支持检查;传输本身仍必须是已注册的。

默认安全

若干默认值从“在任何地方都能工作”转变为“保护连接”。其中每一项都把过去毫无防护建立起来的连接,变成一个会失败并说明原因的连接,因此它们需要明确取舍,而不只是改名。

OPC UA

  • security-policy 默认变为 Basic256Sha256 而不再是 NONE。受保护的通道要求在通道打开之前就已知服务器的证书,驱动不再在服务发现时回退到比所配置通道更弱的通道——过去它会静默地这样做。可用 server-certificate-file 指定证书,或用 tls.trust-store 指定信任库;如果端点无需服务发现,可设置 discovery=false;若希望像以前一样接受不受保护的通道,则请求 security-policy=NONE。
  • 受保护的通道还需要一对客户端密钥。可用 tls.keystore(配合 tls.keystore-password 和 tls.keystore-type)提供,否则驱动会生成一张一次性的自签名证书,而对客户端进行认证的服务器不会接受这样的证书。
  • 对既不签名也不加密的通道,驱动拒绝发送用户名和密码。allow-insecure-credentials=true 仍会发送,但会给出警告。
  • 端点必须同时匹配所请求的安全策略以及所请求的消息安全模式,并且会选中匹配到的最强端点,而不是最弱的。

TLS 传输

TLS 传输现在会检查服务器的证书是否是为它所连接的主机签发的。ignore-common-name 早已声明却从未被读取,因此这项检查过去完全没有发生。

如果连接的设备证书中标明的名称并非实际访问所用的地址,连接现在会失败。tls.trust-store(配合 tls.trust-store-password 和 tls.trust-store-type)用于指定要信任的证书,取代 JVM 自带的公共权威机构;ignore-common-name=true 则恢复旧行为,并记录一条警告说明这一点。

ctrlX

驱动不再信任随驱动 jar 一同发布的博世出厂默认证书,也不再接受与签发名称无关的任意主机证书。连接到仍使用出厂证书的设备现在会失败;allow-factory-default-certificate=true 可恢复旧行为,并附带警告。

plc4x 代理驱动

  • 默认使用 TLS 传输而非明文 TCP。现有的明文连接必须显式指定传输方式:plc4x:tcp://…​。
  • 连接时强制要求用户名/密码认证。不带凭据或凭据无效的连接请求会被拒绝,并以 ACCESS_DENIED 结束握手。请使用新增的 username 和 password 参数进行配置。

日志中的凭据

携带机密的值会在声明处做出标记,无论在 PLC4J 还是 PLC4Go 中,只要配置被记录,它们都会显示为 <redacted>。这取代了以往依据参数名进行猜测的做法——那种做法永远只能跟在参数后面一步。

PLC4Go 过去会在 debug 级别原样记录连接字符串,因此密码曾在二十处调用点以明文进入日志。现在不会再这样了。嵌套在另一个连接字符串内部的连接字符串——即代理驱动的 remote-connection-string——会作为连接字符串本身被脱敏。

消息嵌套深度有上限

每个生成的解析器都会拒绝类型嵌套深度超过 1024 层的消息,在 Java、Go、C 和 Python 中皆是如此。有些类型包含自身——BACnet 的构造数据中嵌套着更多构造数据,类型 24 的 OPC UA 变体中嵌套着更多变体——因此值树的深度由发送方决定,而在线路上每深一层只需花费一个字节。

为确实嵌套更深的消息设置 PLC4X_MAX_NESTING_DEPTH。它在所有绑定中含义相同;若取值不是正数,则保留默认值并给出警告。项目自身测试套件中最深的消息嵌套了 36 层。

在此过程中,PLC4Go 的默认值从 255 提升到了 1024,因此无论哪个绑定读取,这个变量的同一设置值现在都代表同一深度。

协议层面的修正

这些改动会影响线路上传输的内容,或影响某个值被解码后的结果。它们属于修正,但已经适应旧行为的系统需要留意。

  • S7 DATE_AND_TIME:星期字段的半字节现在按照 S7 的方式编号——周日为 1,周六为 7。两个绑定此前都用各自日期库中的值填充它,而该库从周一开始计数,因此写入 PLC 的每一个 DATE_AND_TIME 所携带的星期值都少了一天。只有 IEC61131_DATE_AND_TIME 受影响;DTL 变体早已使用西门子的编号方式。
  • IEC 60870-5-104:S 格式确认帧现在按照标准要求,由所接收帧的发送序号推导得出。此前驱动发送的是完全不同的序号。会检查确认帧的站点将看到不同的——也是正确的——数值。
  • EtherNet/IP 数据类型码:LWORD 从 0x00D3 移到了 0x00D4,STRINGI 从 0x00DD 移到了 0x00DE。此前每个类型都与另一个类型共用同一个值,而重复的键会从生成的查找表中被静默丢弃,导致二者根本无法解析。任何硬编码旧 LWORD 值的代码,实际寻址的都是一个 DWORD。
  • EtherNet/IP 字符串写入现在发出的结构与读取路径解析的结构一致,因此驱动写入的内容读回来是同一个值。以 :STRING 寻址的写入现会被拒绝——请以 :STRUCTURED 写入字符串。

不合理的元素数量将被拒绝

标签地址中若指定了不合理的元素数量,现在会被视为无效地址,而不再由驱动照做。元素计数是一次分配请求,过去它被照单全收。这会影响 S7、ADS、Firmata、Modbus、Profinet、Profinet-NG 以及模拟驱动。在所有这些驱动中,过大到无法表示为数字的计数,过去会以 NumberFormatException 的形式逸出,而不是标签解析器所承诺的无效标签错误。

接下来阅读

评论

登录后参与评论

正在加载评论…