STOMP协议规范
原文: STOMP Protocol Specification, Version 1.2
摘要
STOMP是一个简单的可互操作的协议, 被用于通过中间服务器在客户端之间进行异步消息传递。它定义了一种在客户端与服务端进行消息传递的文本格式.
STOMP已经被使用了很多年,并且支持很多消息brokers和客户端库。这个规范定义STOMP
1.2协议以及对
1.1版本的更新。
发送反馈到
stomp-spec@googlegroups.com.
概述
概述
背景
背景
由于需要用脚本语言如
Ruby,
Python,
Perl去连接企业级的消息
brokers, STOMP产生了.在这种情况下,STMOP实现了一些简单的操作,比如可靠地发送单一的消息,然后断开或者从目的地消费所有消息。
STOMP是除
AMQP开放消息协议之外地另外一个选择, 实现了被用在JMS brokers中特定的有线协议,比如
OpenWire. 它仅仅是实现通用消息操作中的一部分,并非想要覆盖全面的消息API.
STOMP目前已经是个成熟的协议,在
wire-level方面, 它提供了一些简单的用例,但仍保持其核心设计原则:简单性和互操作性。 ### 协议概述
STOMP是基于frame的协议, 与HTTP的frame相似.一个
frame包含一个
command,一系列可选的
headers和
body.STOMP虽然是基于消息但同于也允许传递二进制消息。STMOP的默认消息格式是
UTF-8,但是在消息体中同样支持其他格式编码。
STOMP服务器就好像是一系列的目的地, 消息会被发送到这里。STOMP协议把目的地当作不透明的字符串,其语法是服务端具体的实现。 此外STOMP没有定义目的地的交付语义是什么。 交付,或“消息交换”,语义的目的地可以从服务器到服务器,甚至从目的地到目的地。这使得服务器有可创造性的语义,去支持STOMP。
STOMP client的用户代理可以充当两个角色(可能同时): * 作为生产者,通过
SENDframe发送消息到server * 作为消费者,发送
SUBSCRIBEframe到目的地并且通过
MESSAGEframe从server获取消息。
STOMP版本之间的变化
STOMP版本之间的变化
STOMP 1.2 大部分向后兼容1.1. 有两点不兼容的改变: * 用回车加换行符代替只用换行符结束frame * 简化了消息应答,用专用的header
除此之外,STOMP 1.2并没有增加新特性,而是阐述规格中的一些模糊概念,比如: * 重复的frame header条目 *
content-length和
content-typeheaders的用法 * 必须支持servers STOMP frame * 连接延迟 * 作用域,订阅的唯一,事务的标示符 *
RECEIPTframe的含义
设计哲学
设计哲学
简易性,互通性是STOMP主要设计哲学.
STOMP被设计成为轻量级的协议,它很容易用其他语言在client和server实现。这就意味着servers的架构没有太多的约束,以及没有太多的特性比如目的地命名空间,可靠的语法需要去实现。
在这份规格书里面,注意,我们没有明确定义的STOMP 1.2 servers特性。你应该查阅STMOMP servers 文档去获得这些特性的详细描述。
一致性
一致性
RFC 2119中详细地解释了
MUST,
MUST NOT,
REQUIRED,
SHALL,
SHALL NOT,
SHOULD,
SHOULD NOT,
RECOMMENDED,
MAY, 和
OPTIONAL这些关键字
为了阻止来自服务端地攻击,保护内存溢出,消除平台限制,限制了不受约束的输入。
规格中一致性的级别适用于STOMP clients and STOMP servers.
STOMP Frames
STOMP Frames
STOMP是基于帧的协议,它假定底层为一个2-way的可靠流的网络协议(如TCP)。客户端和服务器通信使用STOMP帧流通讯。帧的结构看起来像:
COMMAND header1:value1 header2:value2 Body^@
帧以command字符串开始,以EOL结束,其中包括可选回车符(13字节),紧接着是换行符(10字节)。command下面是0个或多个
NULL字节。本文档中的例子将使用
^@,在ASCII中用control-@表示,代表NULL字节。NULL字节可以选择跟多个
EOLs。欲了解更多关于STOMP帧的详细信息,请参阅Augmented BNF节本文件。
本文档中引用的所有command 和header 名字都是大小写敏感的.
编码方式
编码方式
commands和headers 都是用UTF-8编码的.在用UTF-8编码的headers中除了
CONNECT和
CONNECTED帧以外,任何的回车符,换行符,colon found(?)都将被转义.
转义的目的在于允许header中的键值包含那些把
octets当作值的frame header.
为了向后兼容STOMP 1.0,
CONNECT和
CONNECTED不会转义回车符,换行符,colon found(?)
C风格的字符串转义被用在UTF-8编码的headers中去转义回车符,换行符以及colon found.当解码headers时,必须使用下列转换: * \r (octet 92 and 114) translates to carriage return (octet 13) * \n (octet 92 and 110) translates to line feed (octet 10) * \c (octet 92 and 99) translates to : (octet 58) * \\ (octet 92 and 92) translates to \ (octet 92)
未定义转义序列如
\t(octet 92 and 116)必须被视为一个致命的错误。相反,当编码帧头,必须使用逆转变.
The STOMP 1.0 specification included many example frames with padding in the headers and many servers and clients were implemented to trim or pad header values. This causes problems if applications want to send headers that SHOULD not get trimmed. In STOMP 1.2, clients and servers MUST never trim or pad headers with spaces.
Body
Body
只有
SEND,
MESSAGE, 和
ERROR帧有body。所有其他的帧
不能有body。
标准header
标准header
大多数被用的header都有特殊的含义。
Header content-length
Header content-length
所有的帧可能都包括有
content-length的header。它定义了消息体的大小。如果header包含了
content-length, 包含空字节的消息体的最大字节数不能超过这个数. 帧仍然需要以空字节结束。
如帧体存在,
SEND,
MESSAGE 和
ERROR帧应该包含
content-length.如果帧体包含空字节,那么这个帧必须包括
content-length.
Header content-type
Header content-type
如果帧体存在,
SEND,
MESSAGE 和
ERROR帧应该包含
content-type帮助接受者去理解帧体.如果设置了
content-type, 它的值必须是描述帧体格式的
MINE类型.否则,接收者应该认为帧体格式为二进制Blob.
以
text/开头的MINE类型的默认文本编码是
UTF-8. 如果你正在用一个基于MINE类型的不同编码, 你应该添加
;charset=
text/html;charset=utf-16.
;charset=
text/ MINE类型后去作为说明。UTF-8编码的XML是个很好的例子。它的编码被设置为
application/xml;charset=utf-8.
所有STOMP客户端和服务端必须支持
UTF-8编码和解码。因此,为了最大限度地使用在异构环境中的互操作性,建议基于文本的内容使用UTF-8编码.
Header receipt
Header receipt
任何除了
CONNECT的客户端帧可以为
receipt header指定任何值。这会让服务端应答带有
RECEIPT的客户端帧的处理过程。
Repeated Header Entries
Repeated Header Entries
Since messaging systems can be organized in store and forward topologies, similar to SMTP, a message may traverse several messaging servers before reaching a consumer. A STOMP server MAY ‘update’ header values by either prepending headers to the message or modifying a header in-place in the message.
如果client或者server受到重复的header条目,只有第一个会被用作header条目的值。其他的值仅仅用来维持状态改变,或者被丢弃。
例如,如果client收到:
MESSAGE foo:World foo:Hello ^@
foo header的值为
World.
大小限制
大小限制
为了客户端滥用服务端的内存分配,服务端可以设置可分配的内存大小:
单个帧允许帧头的个数header中每一行的最大长度帧体的大小
如果超出了这些限制,server应该向client发送一个
error frame,然后关闭连接.
连接延迟
连接延迟
STOMP servers必须支持client快速地连接server和断开连接。 这意味着server在连接重置前只允许被关闭的连接短时间地延迟.
结果就是,在socket重置前client可能不会收到server发来的最后一个frame(比如
ERROR或者
RECEIPTframe去应答
DISCONNECTframe)
Connecting
Connecting
STOMP client通过
CONNECTframe与server建立流或者TCP连接.
CONNECT accept-version:1.2 host:stomp.github.org ^@
如果server收到请求,将返回
CONNECTEDframe:
CONNECTED version:1.2 ^@
server能拒绝所有的连接请求。server应该响应
ERRORframe去说明为什么连接被拒绝然后关闭连接。
CONNECT or STOMP Frame
CONNECT or STOMP Frame
STOMP servers 处理
STOMPframe必须和处理
CONNECTframe一样。STOMP
1.2 clients应该继续使用
CONNECTcommand去向后兼容
1.0.
使用
STOMPframe的clients只能连接上STOMP
1.2 servers(以及一些STOMP1.1 servers),但是好处在于协议探针能够从HTTP连接中区分开STOMP连接。
STOMP 1.2 clients
必须设置以下headers: *
accept-version: clients支持的STOMP的版本号。详情见Protocol_Negotiation *
host:client希望连接的虚拟主机名字,建议设置已经连接的socket为主机名,或者任何名字。如果headers没有匹配到任何可用的虚拟主机,支持虚拟主机的servers将选择默认的虚拟主机或者拒绝连接。
STOMP 1.2 clients
可选择设置以下headers: *
login: 用于在server验证的用户id *
passcode: 用于在server验证的密码 *
heart-beat: 心跳设置
CONNECTED Frame
CONNECTED Frame
STOMP 1.2 servers
必须设置以下headers:
version: 会话中STOMP版本。详情见Protocol_Negotiation
STOMP 1.2 servers
可选择设置以下headers:
heart-beat: 心跳设置session: 唯一的会话identifier
server: 描述STOMP server信息。它必须包含
server-name,可以包含一些注释信息(用空格分开)
server-name后面也可以带着可选的版本号.
server = name ["/" version] *(comment)
例如:
server:Apache/1.3.9
Protocol Negotiation
Protocol Negotiation
STOMP1.1 以后的版本,
CONNECTframe必须包括
accept-versionheader.它的值为clients支持的STOMP版本号,多个版本号用
,隔开。如果不存在
accept-versionheader,那么表明clients只支持1.0.
在一次会话中将使用双方都支持的最高版本。
例如,如果client发送:
CONNECT accept-version:1.0,1.1,2.0 host:stomp.github.org ^@
server将返回与客户端同时支持的最高版本。
CONNECTED version:1.1 ^@
如果client和server不支持共同的协议版本,server必须返回如下的
ERRORframe,然后断开连接。
ERROR version:1.2,2.1 content-type:text/plain Supported protocol versions are 1.2 2.1^@
心跳
心跳
心跳被用于去测试底层TCP连接的可用性,确保远端服务处于活动状态。
要使用心跳,每个部分必须声明它能干什么以及想要其他部分干什么. 通过在
CONNECT和
CONNECTEDframe中增加
heart-beatheader, 让心跳在会话开始被定义好。
heart-beatheader必须包含两个用逗号隔开的正整数。
第一个数字代表发送方能做什么: *
0表示它不能发送心跳 * 否则它是能保证两次心跳的最小毫秒数
第二个数字代表发送方能获得什么: *
0表示它不想接收心跳 * 否则它表示两次心跳期望的毫秒数
heart-beatheader是
OPTIONAL的。没有的话会被当作
heart-beat:0,0header 处理,意思就是说它不会发送心跳并且不想接收心跳。
heart-beatheader提供了足够的信息去了解每个部分心跳是否可用,发送到哪里,频率的大小.
原始frame像这个样子: