看了ZMTP 2.0的协议介绍,我们也看看1.0,想看原文的在这里。
ZeroMQ消息传输协议(ZMTP)是一种传输层协议,用于通过连接的传输层(如TCP)在两个对等程序之间交换消息。本文档描述了由0MQ/2.x实现的ZMTP/1.0。
理论上,ZMTP应该允许实现它的程序之间的完全互操作性。但是,部分必要的语义只在libzmq
的代码中定义。我们希望随着时间的推移,这些语义将被正确地提取、抽象、文档化,并通过独立的代码进行验证。
该规范的主要目标是允许独立堆栈和libzmq
堆栈之间的互操作性。第二个目标是充当这个标准化过程的资料架和催化剂。
ZMTP由以下层组成:
组帧层是ZMTP中所有内容的基础。基本传输层(例如由TCP提供)是一个流。ZMTP的帧层将其转换为一系列帧(frame),不分传输方向。帧是指定长度的,因此对端可以安全地拒绝超大的帧。ZMTP的帧设计针对带宽和性能进行了优化。
组帧用于创建结构化消息,而不是将大型消息分解成片段。ZMTP假设对端将读取和处理消息的所有帧,或者完全一帧都不读取和处理。帧特别用于将消息内容从消息地址信封中分离出来(参见内容层)。
无论连接上发生了什么工作,组帧层都是一致的。也就是说,它可以从网线上发送的信息中完全解释。
ZMTP消息由1个或多个帧组成。
一个ZMTP帧由一个长度(length)、一个标志(flag)字段和一个(长度- 1)字节的帧体组成。注意: 长度包括flags字段,所以空帧的长度为1。
对于长度为1到254字节的帧,长度应该被编码为单个字节。帧的最小有效长度是1字节,因此长度为0是无效的,这样的帧应该被默默地丢弃。
对于长度为255或更大的帧,长度应该被编码为一个值为255的单字节体,然后是按网络字节顺序编码为64位无符号整数的长度。对于长度为1到254字节的帧,也可以使用这种编码。
标志字段由包含各种控制标志的单个字节组成。位0是最低位。
下面的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连接是双向和异步的。也就是说,任何一端都可以在任何时间向另一端发送消息。
连接的每一端都包含一个问候语(greeting),后面跟着零个或多个内容。内容消息是根据内容类型进行格式化的,如内容层规范中所述。
一端(peer)应发送由匿名(anonymous)或身份标识(identity or ID)组成的问候语。匿名问候语由空字符串组成。这将告诉另一端,该连接没有持久性,当连接结束时,与之关联的所有资源都将被删除。有身份标识(ID)的问候语由1到255字节的唯一字符串组成。这告诉另一端将资源与该标识(ID)关联起来,并在连接结束时无限期地保存它们。
标识(ID)不应该以0字节开始,这是为通信端(peer)内部使用保留的。peer可能拒绝身份标识,应该对无限期持有资源的代价保持谨慎。
下面的ABNF语法定义了任意方向的ZMTP连接:
connection = greeting content
greeting = anonymous / identity
anonymous = %x01 idflags
identity = length idflags (%x01-ff) *OCTET
idflags = %00
标识帧的标志字段(idflags)不应该被验证,应该被设置为零。
通过连接发送的ZMTP内容消息的格式和语义取决于该连接方向的内容类型,这在协议中没有指定,但必须由通信端(peer)承担。
以下ABNF语法定义了ZMTP内容:
content = *broadcast / *addressed / *neutral
广播内容用于发布者和订阅者之间。发布者应当发送广播内容。订阅者不得发送任何内容。
以下ABNF语法定义了ZMTP广播内容:
broadcast = message
接收者可以过滤消息。可以使用任何匹配机制(前缀、通配符、regexp)。ZMTP没有对此进行标准化,尽管当前的ZeroMQ实现使用前缀匹配。
寻址内容在请求-应答链中的端点之间使用。在请求-应答链中,任何端点都可以向任何其他端点发送寻址内容。
以下ABNF语法定义了ZMTP寻址内容:
addressed = envelope message
envelope = *more-frame delimiter
delimiter = %x01 more
同行应按下列方式使用信封(envelope):
通过这种方式,对端链可以在转发请求时将地址推送到信封上,并从信封上弹出地址以返回应答。
中性内容用于不需要路由的对端之间。任何一个对端都可以向另一个对端发送中性的内容,尽管特定的对端实现可以忽略来自其对端的内容。
以下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没有尝试安全性,而应用程序可以在其上添加一层。