35/FILEMQ

35/FILEMQ

文件消息队列协议

文件消息队列协议 (FILEMQ) 管理客户端和服务器之间的文件传递。FILEMQ 运行于 ZeroMQ ZMTP v3 协议之上。这是 FILEMQ 协议的第 2 版。

前言

版权所有 (c) 2009-2014 iMatix 公司

本规范是自由软件;您可以根据自由软件基金会发布的 GNU 通用公共许可协议的条款(第三版或您选择的任何更高版本)重新分发和/或修改它。本规范发布是希望它有所帮助,但不提供任何担保;甚至不包括适销性或适合特定用途的默示担保。请参阅 GNU 通用公共许可协议了解更多详情。您应该已经随同本程序收到一份 GNU 通用公共许可协议的副本;如果没有,请参阅 https://gnu.ac.cn/licenses

本规范是一个 自由开放标准,受数字标准组织 面向共识的规范系统管辖。

本文档中的关键词 “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY” 和 “OPTIONAL” 应按照 RFC 2119 中的描述进行解释。

目标

FILEMQ 协议定义了一种使用发布-订阅模式进行广域文件分发的机制。其目标是

  • 允许客户端“订阅”服务器托管的目录,而无需关于将在这些目录上创建的文件的任何带外知识。
  • 向客户端提供高速的分块文件传递。
  • 允许客户端任意地取消和重新开始文件传输。
  • 完全安全,使用 ZMTP v3 安全机制。

实现

形式化语法

以下 ABNF 语法定义了 FILEMQ 协议

FILEMQ          = open-peering *use-peering [ close-peering ]

open-peering    = C:OHAI ( S:OHAI-OK / error )

use-peering     = C:ICANHAZ ( S:ICANHAZ-OK / error )
                / C:NOM
                / S:CHEEZBURGER
                / C:HUGZ S:HUGZ-OK
                / S:HUGZ C:HUGZ-OK

close-peering   = C:KTHXBAI / S:KTHXBAI

error           = S:SRSLY / S:RTFM

;     Client opens peering
ohai            = signature %d1 protocol version
signature       = %xAA %xA3             ; two octets
protocol        = string                ; Constant "FILEMQ"
version         = number-2              ; Protocol version 2

;     Server grants the client access
ohai_ok         = signature %d4

;     Client subscribes to a path
icanhaz         = signature %d5 path options cache
path            = string                ; Full path or path prefix
options         = dictionary            ; Subscription options
cache           = dictionary            ; File SHA-1 signatures

;     Server confirms the subscription
icanhaz_ok      = signature %d6

;     Client sends credit to the server
nom             = signature %d7 credit sequence
credit          = number-8              ; Credit, in bytes
sequence        = number-8              ; Chunk sequence, 0 and up

;     The server sends a file chunk
cheezburger     = signature %d8 sequence operation filename offset eof headers chunk
sequence        = number-8              ; File offset in bytes
operation       = number-1              ; Create=%d1 delete=%d2
filename        = string                ; Relative name of file
offset          = number-8              ; File offset in bytes
eof             = number-1              ; Last chunk in file?
headers         = dictionary            ; File properties
chunk           = chunk                 ; Data chunk

;     Client or server sends a heartbeat
hugz            = signature %d9

;     Client or server answers a heartbeat
hugz_ok         = signature %d10

;     Client closes the peering
kthxbai         = signature %d11

;     Server refuses client due to access rights
srsly           = signature %d128 reason
reason          = string                ; Printable explanation

;     Server tells client it sent an invalid message
rtfm            = signature %d129 reason
reason          = string                ; Printable explanation

; A list of name/value pairs
dictionary      = dict-count *( dict-name dict-value )
dict-count      = number-4
dict-value      = longstr
dict-name       = string

; A chunk has 4-octet length + binary contents
chunk           = number-4 *OCTET

; Strings are always length + text contents
string          = number-1 *VCHAR
longstr         = number-4 *VCHAR

; Numbers are unsigned integers in network byte order
number-1        = 1OCTET
number-2        = 2OCTET
number-4        = 4OCTET
number-8        = 8OCTET

互联模型

ZeroMQ 套接字类型

服务器 **必须** 创建一个 ROUTER 套接字,并 **应该** 将其绑定到端口 5670,这是文件消息队列协议 (FILEMQ) 在互联网号码分配机构 (IANA) 注册的端口。服务器 **可以** 将其 ROUTER 套接字绑定到临时端口范围 (%C000x - %FFFFx) 中的其他端口。客户端 **必须** 创建一个 DEALER 套接字并将其连接到服务器的 ROUTER 主机和端口。

注意,ROUTER 套接字会向调用者提供在套接字上接收到的任何消息的发送者的连接标识,该标识作为消息中其他帧之前的身份帧出现。

协议签名

每条 ZeroMQ 消息 **必须** 以 FILEMQ 协议签名 %xAA %xA3 开始。服务器和客户端接收到任何不以这两个八位字节开始的消息时,**必须** 悄悄地将其丢弃。

这种机制特别为绑定到临时端口的服务器设计,这些临时端口可能之前已被其他协议使用,并且可能仍有对等方尝试连接到这些端口。它也是一个用于检测格式错误消息的通用快速失败机制。

连接状态

服务器接收到未预期的命令时,**必须** 回复 RTFM 命令。客户端接收到 RTFM 命令时,**必须** 关闭其 DEALER 连接并开始一个新的连接。

FILEMQ 命令

OHAI 命令

客户端 **必须** 通过向服务器发送 OHAI 命令来开始新的连接。此命令标识协议和版本。这是为了允许版本检测。

如果服务器不支持请求的协议版本,它 **必须** 回复 RTFM 命令。客户端 **可以** 尝试使用更低的协议版本再次连接。

如果服务器接受 OHAI 命令,它 **必须** 回复 OHAI-OK 命令。如果服务器由于其他原因不接受 OHAI 命令,它 **必须** 回复 SRSLY 命令。

OHAI-OK 命令

当服务器在 OHAI 命令后授予客户端访问权时,它 **必须** 回复 OHAI-OK 命令。

ICANHAZ 命令

客户端 **可以** 通过向服务器发送 ICANHAZ 命令来订阅任意数量的虚拟路径。客户端 **可以** 指定完整路径,或 **可以** 指定部分路径,这用作前缀匹配。路径 **必须** 以 “/” 开头,因此路径 “/” 订阅所有内容。

‘path’ 不必在服务器上存在。也就是说,客户端可以请求将来某个时间将在服务器上存在的路径。

‘options’ 字段向服务器提供额外信息。服务器 **应该** 实现这些选项

  • RESYNC=1- 如果客户端设置此项,服务器 **必须** 将虚拟路径的全部内容发送给客户端,但客户端已有的文件除外,这些文件通过其在 ‘cache’ 字段中的 SHA-1 摘要标识。

当客户端指定 RESYNC 选项时,‘cache’ 字典字段会告诉服务器客户端已经拥有哪些文件。‘cache’ 字典中的每个条目都是一个 “filename=digest” 键/值对,其中 digest **必须** 是可打印十六进制格式的 SHA-1 摘要。如果文件名以 ‘/’ 开头,则 **应该** 以路径开头,否则服务器 **必须** 忽略它。如果文件名不以 ‘/’ 开头,则服务器 **必须** 将其视为相对于路径。

ICANHAZ-OK 命令

当服务器接受订阅时,它 **必须** 回复 ICANHAZ-OK 命令。如果服务器拒绝订阅,它 **必须** 回复 SRSLY 命令,并丢弃来自该客户端的任何后续命令。

NOM 命令

客户端 **必须** 通过向服务器发送信用(credit)来启动数据传输。服务器 **必须** 只向客户端发送与其拥有的信用等量的数据。信用是一个字节量,对应于实际的文件内容(但不包括命令本身使用的字节)。

客户端在从服务器接收到 OHAI-OK 后,**可以** 在任何时候发送 NOM 命令。服务器 **禁止** 直接响应 NOM 命令。

CHEEZBURGER 命令

服务器 **必须** 使用 CHEEZBURGER 命令向客户端发送文件内容。每个 CHEEZBURGER 命令将传递从特定偏移量开始的文件数据块。服务器 **必须** 将单个文件的内容作为连续的块发送,客户端 **可以** 依赖此行为。

headers 字段保留供将来使用。

HUGZ 命令

服务器或客户端在服务器向客户端发送 OHAI-OK 且客户端已接收到之后,**可以** 在任何时候发送心跳命令。

HUGZ 命令作为心跳,表明对等方在线。服务器和客户端 **必须** 将来自对等方的任何命令视为对等方在线的标志。

因此,对等方可以选择只在没有向另一个对等方发送任何其他流量时发送 HUGZ。

HUGZ-OK 命令

对等方接收到 HUGZ 命令时,**必须** 回复 HUGZ-OK 命令。这允许由一个对等方负责所有心跳机制。

KTHXBAI 命令

客户端 **可以** 通过向服务器发送 KTHXBAI 命令来结束连接。服务器 **禁止** 响应此命令。

SRSLY 命令

服务器接收到任何失败的服务器资源访问尝试时,**必须** 回复 SRSLY 命令。这包括失败的订阅。当客户端接收到 SRSLY 命令时,它 **应该** 关闭连接,如果需要,使用新的认证凭据重新连接。

RTFM 命令

服务器接收到无效命令时,**必须** 通过发送 RTFM 来响应。注意,对于发送了无效协议签名的客户端,服务器 **禁止** 发送 RTFM。当客户端接收到 RTFM 命令时,它 **应该** 关闭连接并且不重新连接。

安全方面

FILEMQ v2 使用 ZMTP v3 传输层安全机制(NULL、PLAIN、CURVE 等)。用于文件缓存标识的 SHA-1 摘要没有安全含义。

参考实现

本协议的参考实现位于 filemq.org