Simple (or Streaming) Text Oriented Message Protocol (STOMP) 是一種單純的以純文字為基礎的協定,通常用在訊息導向的 client-server 互動的訊息交換標準,所以會在 Message Queue 以及 WebSocket 看到使用這個 Protocol 傳遞訊息。
Commands
STOMP 類似 HTTP protocol,在 client 傳送給 server 定義了以下這些 Commands
- CONNECT
- SEND
- SUBSCRIBE
- UNSUBSCRIBE
- BEGIN
- COMMIT
- ABORT
- ACK
- NACK
- DISCONNECT
在 Server 傳送給 client 定義了以下的 commands
- CONNECTED
- MESSAGE
- RECEIPT
- ERROR
在規格中,稱呼每一則傳遞的訊息為 frame,frame 的第一行都是 command,後面跟著多行 key:value 的 headers,然後有一行空白,最後面是 body content,這樣的訊息格式跟 http 完全一樣
frame 結束時,要有一個 NULL octet,在規格文件標記為 ^@
只有 SEND, MESSAG, ERROR 這三個 frame 能夠有 body,其他 frames 不能有 body
Headers
commands 跟 headers 必須使用 UTF-8 encoding,在 parsing header 時,必須要做這樣的轉換
\r (0x5C, 0x72) 要轉換為 carriage return (0x0D)
\n (0x5C, 0x6E) 要轉換為 line feed (0x0A)
\c (0x5C, 0x63) 要轉換為 : (0x3A)
\\ (0x5C, 0x5C) 要轉換為 \ (0x5C)
在 header 的部分,除了因應自己的需求,要定義的 headers 以外,建議要定義這些標準的 header
content-length
content-type
這兩個 headers 類似 http protocol,就是整個 frame 的長度,以及 content 的內容格式
為避免惡意的 client,故意傳送非常大的 frame,把 server 的訊息 buffer 撐爆,server 可以限制以下這些部分的長度
單一 frame 裡面可使用的 header 數量
每一行 header 的最大長度
frame body 的最大長度
在 Spec 裡面,將 frame 區分為 Connecting, Client, Server 三個部分
Connecting
client 連線時,要發送 CONNECT
CONNECT
accept-version:1.2
host:stomp.github.org
^@
連線也可加上其他 headers,例如 login 帳號,passcode 密碼,heart-beat
server 接受連線要回應
CONNECTED
version:1.2
^@
還可以加上 session 代表 session id,server 代表 server name
CONNECT
accept-version:1.0,1.1,2.0
host:stomp.github.org
^@
完全不接受連線,就回應ERROR,這樣是說明 client 版本不符
ERROR
version:1.2,2.1
content-type:text/plain
Supported protocol versions are 1.2 2.1^@
Heart-beating
因為 TCP 連線有可能因為太久沒有資料通過,該連線通道有可能會被網路中兼任一個節點關閉,heart-beating 功能,類似 ping pong,定時發送,維持 TCP 連線。
heart-beat header 格式有兩個正整數,用逗號隔開
第一個正整數代表 sender 的 outgoing heart-beat
0: 表示無法發送 heart-beat
其他: 代表該 sender 保證在多少 milliseconds 之間,可發送 heart-beat
第二個正整數代表 sender 期待收到的 heart-beat
0: 表示不需要接收 heart-beat
其他: 代表該 sender 希望在多少 milliseconds 之間,可收到 heart-beat
CONNECT
heart-beat:<cx>,<cy>
CONNECTED
heart-beat:<sx>,<sy>
Client Frames
SEND
SUBSCRIBE
UNSUBSCRIBE
BEGIN
COMMIT
ABORT
ACK
NACK
DISCONNECT
SEND
send message to a destination
SEND
destination:/queue/a
content-type:text/plain
hello queue a
^@
SUBSCRIBE
註冊要 listen to a given destination
SUBSCRIBE
id:0
destination:/queue/foo
ack:client
^@
UNSUBSCRIBE
UNSUBSCRIBE
id:0
^@
ACK
acknowledge 確認收到某個訊息,如果有 transaction header,代表這個 ACK 是某個 transaction 的一部分
ACK
id:12345
transaction:tx1
^@
NACK
ACK 的相反
BEGIN
開始某個 transaction
BEGIN
transaction:tx1
^@
COMMIT
commit transaction
COMMIT
transaction:tx1
^@
ABORT
roll back a transaction
ABORT
transaction:tx1
^@
DISCONNECT
client 在關閉 TCP connection 之前,發送 DISCONNECT,正式通知 server 要關閉連線
client
DISCONNECT
receipt:77
^@
server response
RECEIPT
receipt-id:77
^@
client 在收到 RECEIPT 後,才正式關閉連線
Server Frames
MESSAGE
RECEIPT
ERROR
MESSAGE
傳送訊息給 destination,一定要加上 message-id header
MESSAGE
subscription:0
message-id:007
destination:/queue/a
content-type:text/plain
hello queue a^@
RECEIPT
server 確認有收到 client 發送的某一個 FRAME
RECEIPT
receipt-id:message-12345
^@
ERROR
錯誤發生時,server 發送給 client
ERROR
receipt-id:message-12345
content-type:text/plain
content-length:170
message:malformed frame received
The message:
-----
MESSAGE
destined:/queue/a
receipt:message-12345
Hello queue a!
-----
Did not contain a destination header, which is REQUIRED
for message propagation.
^@
Frames and Headers
除了上面提到,標準的 headers: content-length, content-type, receipt,所有 frames 建議必要使用與選擇性使用的 headers 如下
CONNECT
orSTOMP
- REQUIRED:
accept-version
,host
- OPTIONAL:
login
,passcode
,heart-beat
- REQUIRED:
CONNECTED
- REQUIRED:
version
- OPTIONAL:
session
,server
,heart-beat
- REQUIRED:
SEND
- REQUIRED:
destination
- OPTIONAL:
transaction
- REQUIRED:
SUBSCRIBE
- REQUIRED:
destination
,id
- OPTIONAL:
ack
- REQUIRED:
UNSUBSCRIBE
- REQUIRED:
id
- OPTIONAL: none
- REQUIRED:
ACK
orNACK
- REQUIRED:
id
- OPTIONAL:
transaction
- REQUIRED:
BEGIN
orCOMMIT
orABORT
- REQUIRED:
transaction
- OPTIONAL: none
- REQUIRED:
DISCONNECT
- REQUIRED: none
- OPTIONAL:
receipt
MESSAGE
- REQUIRED:
destination
,message-id
,subscription
- OPTIONAL:
ack
- REQUIRED:
RECEIPT
- REQUIRED:
receipt-id
- OPTIONAL: none
- REQUIRED:
ERROR
- REQUIRED: none
- OPTIONAL:
message
雖然規格有提到這些 header 建議,但實際上,這份規格比較接近是針對 messaging system 的 frame 建議。
常常會看到的是只使用了類似 http frame 的格式,每一則傳遞的訊息為 frame,frame 的第一行都是 command,後面跟著多行 key:value 的 headers,然後有一行空白,最後面是 body content,就只有符合這樣的使用規則,其他部分的內容,都是讓 application 自己決定該怎麼使用。
header, body 的內容,都是讓 application 自己決定自己的 client-server 溝通的 protocol 訊息內容。
沒有留言:
張貼留言