13/ZMTP

13/ZMTP

ZeroMQ 消息传输协议

ZeroMQ 消息传输协议 (ZMTP) 是一种传输层协议,用于在诸如 TCP 的连接传输层上在两个对等方之间交换消息。本文档描述了由 0MQ/2.x 代软件实现的 ZMTP/1.0。

许可证

版权所有 (c) 2009-2012 iMatix Corporation

本规范是自由软件;您可以在自由软件基金会发布的 GNU 通用公共许可证(任选第 3 版或任何更高版本)的条款下再分发和/或修改它。

本规范分发时希望它会有用,但不做任何担保;甚至没有适销性或特定用途适用性的默示担保。更多详细信息请参阅 GNU 通用公共许可证。

您应该已经随本程序收到了 GNU 通用公共许可证的副本;如果未收到,请参阅 https://gnu.ac.cn/licenses

变更流程

本规范是一个自由开放标准(请参阅“自由开放标准的定义”),并由数字标准组织的一致性导向规范系统(COSS)管理(请参阅“一致性导向规范系统”)。

语言

本文档中的关键词“MUST”(必须)、“MUST NOT”(禁止)、“REQUIRED”(要求)、“SHALL”(应)、“SHALL NOT”(不应)、“SHOULD”(应该)、“SHOULD NOT”(不应该)、“RECOMMENDED”(推荐)、“MAY”(可)和“OPTIONAL”(可选)的解释应按照 RFC 2119 中的描述进行(请参阅“在 RFC 中用于指示需求级别的关键词”)。

目标

ZeroMQ 消息传输协议 (ZMTP) 是一种传输层协议,用于在诸如 TCP 的连接传输层上在两个对等方之间交换消息。本文档描述了由 0MQ/2.x 代软件实现的 ZMTP/1.0。

理论上,ZMTP 应该允许实现它的产品之间完全互操作。然而,必要语义的部分内容仅在 libzmq 的代码中定义。我们希望随着时间的推移,这些语义能够被正确地提取、抽象、文档化,并由独立的实现进行验证。

本规范的主要目标是允许独立实现栈与 libzmq 实现栈之间的互操作。次要目标是充当这个标准化过程的容器和催化剂。

架构

ZMTP 由以下层组成

  • 一个帧层,它在底层传输上施加了大小前缀的规则性。
  • 一个连接层,它允许两个对等方交换消息。
  • 一个内容层,它定义了根据套接字类型如何格式化应用程序数据。

帧层

引言

帧层是 ZMTP 中所有内容的基础。基本传输层(例如 TCP 提供)是一个流。ZMTP 的帧层将其转换为一系列帧,可以是任一方向。帧指定了长度,因此对等方可以安全地拒绝过大的帧。ZMTP 的帧设计针对带宽和性能进行了优化。

帧用于创建结构化消息,而不是将大消息分解成片段。ZMTP 假定对等方将读取和处理消息的所有帧,或者完全不处理。帧特别用于将消息内容与消息地址信封分离(参见内容层)。

无论连接上正在发生什么工作,帧层都是一致的。也就是说,它可以完全根据线路上发送的信息进行解释。

规范

一个 ZMTP 消息由 1 个或多个帧组成。

一个 ZMTP 帧由一个长度字段、一个标志字段以及一个长度为(长度 - 1)字节的帧组成。注意:长度包含标志字段,因此空帧的长度为 1。

对于长度为 1 到 254 字节的帧,长度 SHOULD BE(应该)编码为一个字节。帧的最小有效长度为 1 字节,因此长度为 0 是无效的,并且此类帧 SHOULD be(应该)静默丢弃。

对于长度为 255 或更大的帧,长度 SHALL BE(应)编码为一个值为 255 的字节,后跟编码为网络字节序的 64 位无符号整数长度。对于长度为 1 到 254 字节的帧,此编码 MAY be(可)用于。

标志字段由一个包含各种控制标志的字节组成。位 0 是最低有效位。

  • 位 0 (MORE):后续更多帧。值为 0 表示没有更多帧要跟随。值为 1 表示将有更多帧跟随。对于仅包含一个帧的消息,MORE 标志 MUST be(必须)为 0。

  • 位 1-7:保留。位 1-7 保留供将来使用,并且 SHOULD be(应该)为零。

以下 ABNF 语法定义了一个 ZMTP 消息

message     = *more-frame final-frame
more-frame  = length more body
final-frame = length final body
length      = OCTET / (%xFF 8OCTET)
more        = %x01
final       = %x00
body        = *OCTET

以下图示显示了长度为 1 到 254 字节的帧的布局

            +----------------+
 Octet 0    | Length         |
            +----------------+
 Octet 1    | Flags          |
            +----------------+- ... ---------------------+
 Octets 2+  | Body                     Length - 1 octets |
            +------------------ ... ---------------------+

以下图示显示了长度为 255 或更多字节的帧的布局

            +----------------+
 Octet 0    | 0xff           |
            +----------------+- ... ---------------------+
 Octets 1-8 | Length                          8 octets   |
            +------------------ ... ---------------------+
 Octet 9    | Flags          |
            +----------------+- ... ---------------------+
 Octets 10+ | Body                     Length - 1 octets |
            +------------------ ... ---------------------+

连接层

引言

连接层提供了一种方式,使对等方在 TCP 连接时互相识别。一个 ZMTP 连接等同于一个 TCP 连接。如果对等方断开并重新连接,这被视为两个独立的 ZMTP 连接。

规范

一个 ZMTP 连接是双向且异步的。也就是说,任一对等方 MAY send(可发送)消息给另一个对等方在任何时间。

连接的每一侧由一个问候消息,后跟零个或多个内容消息组成。内容消息根据内容类型进行格式化,如内容层规范中所解释。

对等方 SHALL send(应发送)一个问候消息,由一个匿名消息或一个身份消息组成。匿名问候消息由一个空字符串组成。这告诉另一个对等方,此连接没有持久性,连接结束时所有关联资源都可以被删除。身份问候消息由一个 1 到 255 字节的唯一字符串组成。这告诉另一个对等方将资源与该身份关联,并在连接结束时无限期地持有它们。

身份 SHOULD NOT(不应该)以零字节开头,零字节保留用于对等方内部使用。对等方 MAY reject(可拒绝)身份,并且 SHOULD be cautious(应该谨慎)对待无限期持有资源的成本。

以下 ABNF 语法定义了 ZMTP 连接的任一方向

connection  = greeting content
greeting    = anonymous / identity
anonymous   = %x01 idflags
identity    = length idflags (%x01-ff) *OCTET
idflags     = %00

身份帧的标志字节 (idflags) SHALL not be(不应)验证,并且 SHOULD be(应该)设置为零。

内容层

引言

跨连接发送的 ZMTP 内容消息的格式和语义取决于该连接方向的内容类型,内容类型未在协议中指定,但必须由双方对等方假定。

以下 ABNF 语法定义了 ZMTP 内容

content     = *broadcast / *addressed / *neutral

广播内容

广播内容用于发布者和订阅者之间。发布者 SHALL send(应发送)广播内容。订阅者 SHALL NOT send(不应发送)任何内容。

以下 ABNF 语法定义了 ZMTP 广播内容

broadcast   = message

接收方 MAY filter(可过滤)消息。可以使用任何匹配机制(前缀、通配符、正则表达式)。ZMTP 没有标准化这一点,尽管当前的 ZeroMQ 实现使用了前缀匹配。

寻址内容

寻址内容用于请求-回复链中的对等方之间。在请求-回复链中,任一对等方 MAY send(可发送)寻址内容给任何其他对等方。

以下 ABNF 语法定义了 ZMTP 寻址内容

addressed   = envelope message
envelope    = *more-frame delimiter
delimiter   = %x01 more

对等方 SHOULD be used(应该)以下列方式使用信封

  • 当一个对等方向另一个对等方发送请求时,它应该发送一个至少包含分隔符的信封。
  • 当一个对等方将请求从一个对等方转发给另一个对等方时,它应该将原始发送对等方的身份前置到信封中(作为一个身份帧)。
  • 当一个对等方接受请求并用回复响应时,它应该解开并保存包括分隔符在内的完整地址信封,然后将剩余消息传递给应用程序,然后用包括分隔符在内的完整地址信封重新包装应用程序的响应。

通过这种方式,一系列对等方在转发请求时可以将地址推入信封,并在路由回复时将地址从信封中弹出。

中立内容

中立内容用于不需要路由的对等方之间。任一对等方 MAY send(可发送)中立内容给另一个对等方,尽管特定的对等方实现 MAY ignore(可忽略)来自其对等方的内容。

以下 ABNF 语法定义了 ZMTP 中立内容

neutral     = message

完整 ZMTP 语法

以下 ABNF 语法定义了完整的 ZMTP 协议

zmtp        = *connection

connection  = greeting content
greeting    = anonymous / identity
anonymous   = %x01 idflags
identity    = length idflags (%x01-ff) *OCTET
idflags     = %00

message     = *more-frame final-frame
more-frame  = length more body
final-frame = length final body
length      = OCTET / (%xFF 8OCTET)
more        = %x01
final       = %x00
body        = *OCTET

content     = *broadcast / *addressed / *neutral

broadcast   = message

addressed   = envelope message
envelope    = *more-frame delimiter
delimiter   = %x01 more

neutral     = message

已知问题

该协议没有版本号。这在 ZMTP 的后续版本中已得到修复,建议实现者至少实现 ZMTP/2.0

在线路格式中没有内容类型的交换或验证。也就是说,对等方必须事先知道它期望从另一个对等方获得的内容类型,以便将其内容正确地解释为广播、寻址或中立类型。这可以通过如上文提出的那样,在连接头部添加内容类型指示符来解决。

长度字段的规范令人惊讶(甚至让阅读规范的专家感到困惑)。它不应该包括标志字段,也不应该包括其他可能的头部字段。这将允许使用长度为零来指定零长度的体。

“身份不能以二进制零开头”的限制继承自软件实现,并且在 ZMTP 中没有明显的语义作用。这一点应该得到澄清。

安全性

ZMTP/1.0 没有尝试提供安全性,应用程序 MAY layer on top(可在其之上分层实现)。