45/ZWS

45/ZWS

ZeroMQ WebSocket 协议 2.0

ZeroMQ WebSocket 2.0 (ZWS2.0) 协议是 ZeroMQ 在 WebSocket 上的映射。

前言

版权所有 (c) 2020 Doron Somech

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

本规范是一个自由开放标准,受数字标准组织(Digital Standards Organization)的共识导向规范系统管辖。

本文档中的关键词“MUST”(必须)、“MUST NOT”(不得)、“REQUIRED”(要求)、“SHALL”(应)、“SHALL NOT”(不应)、“SHOULD”(应该)、“SHOULD NOT”(不应该)、“RECOMMENDED”(建议)、“MAY”(可以)和“OPTIONAL”(可选)应按照RFC 2119中的描述进行解释。

目标

ZeroMQ WebSocket 协议 (ZWS) 是一种在 WebSocket 上进行对等方之间消息交换的传输层协议。本文档描述 ZWS/2.0。

实现

ZWS 连接在客户端和服务器之间成功完成 WebSocket 握手后开始。ZWS 消息是二进制 WebSocket 消息(消息操作码必须是二进制)。

握手

客户端和服务器之间的 WebSocket 连接发起和握手在 rfc6455 中定义。ZWS 握手请求 MUST(必须)包含至少一个协议作为 Sec-WebSocket-Protocol 的一部分。ZWS 定义了以下协议:

  • ZWS2.0 - 无机制。
  • ZWS2.0/NULL - 参见Null 机制
  • ZWS2.0/PLAIN - 参见Plain 机制
  • ZWS2.0/BEARER - 尚未实现

请求的主机和路径部分 MUST(必须)与用户在 connect 方法中设置的一致(例如 zmq_connect(s, "ws://server.example.com/zeromq"))。

客户端请求示例

GET /zeromq HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: ZWS2.0,ZWS2.0/NULL
Sec-WebSocket-Version: 13
Origin: http://example.com

服务器必须选择客户端协议中的一个,并在 WebSocket 握手期间将 Sec-WebSocket-Protocol 设置为所选协议。如果服务器不支持任何协议,服务器应该关闭连接(使用 BAD REQUEST、WebSocket 关闭控制消息或静默断开 TCP 连接)。

服务器回复示例

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: ZWS2.0

无机制

ZWS2.0 的所有实现都必须实现无机制协议,除了 NULL 协议之外提供此协议的原因是针对那些未实现 ZMTP3.0 和各种机制的 ZeroMQ 端口。

无机制的 ZWS2.0 类似于 ZMTP/2,连接双方的第一个消息必须是路由 ID(身份),其余消息是常规消息。

正式 BNF

zws = *connection

connection = identity *message

identity = message-last

;   A message is one or more frames
message = *message-more message-last
message-more = %x01 message-body
message-last = %x00 message-body
message-body = *OCTET

机制

ZWS 定义了 3 种可用的机制:

  • NULL - 如ZMTP3.0 rfc中所述,不实现任何认证。
  • PLAIN - 如ZMTP-PLAIN rfc中所述,实现简单的用户名和密码认证。
  • BEARER - 尚未有规范,实现 bearer 认证。

格式 BNF

;   The protocol consists of zero or more connections
zws = *connection

;   A connection a handshake, and traffic
connection = handshake traffic

;   The handshake consists of at least one command
;   The actual grammar depends on the mechanism
handshake = 1*command

;   Traffic consists of commands and messages intermixed
traffic = *(command | message)

;   A command is a single frame
command = %x02 command-body
command-body = command-name command-data
command-name = OCTET 1*255command-name-char
command-name-char = ALPHA
command-data = *OCTET

;   A message is one or more frames
message = *message-more message-last
message-more = %x01 message-body
message-last = %x00 message-body
message-body = *OCTET

帧格式

每个 ZeroMQ 帧映射到一个 WebSocket 消息。一个帧包含一个 FLAG 字节,后跟帧体。

标志位可以是:

  • 0x00 - 最终消息
  • 0x01 - 更多消息
  • 0x02 - 命令消息

Socket 兼容性

ZWS 实现无需实现所有 socket 类型,可以选择要实现的 socket 类型。

实现 SHOULD(应该)根据接收连接的 socket 的类型强制执行传入连接具有有效的 socket 类型:

  • PAIR 接受来自 PAIR 的连接。
  • PUB 接受来自 SUB 的连接。
  • SUB 接受来自 PUB 的连接。
  • REQ 接受来自 REP 或 ROUTER 的连接。
  • REP 接受来自 REQ 或 DEALER 的连接。
  • DEALER 接受来自 REP、DEALER 或 ROUTER 的连接。
  • ROUTER 接受来自 REQ、DEALER 或 ROUTER 的连接。
  • PULL 接受来自 PUSH 的连接。
  • PUSH 接受来自 PULL 的连接。
  • SERVER 接受来自 CLIENT 的连接。
  • CLIENT 接受来自 SERVER 的连接。
  • RADIO 接受来自 DISH 的连接。
  • DISH 接受来自 RADIO 的连接。
  • SCATTER 接受来自 GATHER 的连接。
  • GATHER 接受来自 SCATTER 的连接。

任何其他 socket 组合 SHOULD(应该)通过静默断开其他对等方连接来处理,并可能记录错误以用于调试目的。

发布-订阅

XPUB 和 XSUB socket 在协议层面上实现为 PUB 和 SUB socket。也就是说,XPUB 和 XSUB 仅是 API 构造。SUB socket 发送订阅消息时,以 0x01 字节开头,后跟订阅体;发送取消订阅消息时,以 0x00 字节 '0' 开头,后跟订阅体。

安全性

各种机制提供认证。然而,ZWS2.0 不尝试对线路进行加密。

客户端支持通过 SSL 隧道,指定 wss 而非 ws,例如 “wss://example.com”。

负载均衡器可能会在到达服务器之前终止 SSL。