當(dāng)一個(gè)節(jié)點(diǎn)發(fā)送像這樣的方法幀時(shí),它總是會(huì)遵循一個(gè)內(nèi)容頭幀(conent header frame)和零個(gè)或多個(gè)內(nèi)容體幀(content body frame)的形式.
當(dāng)一個(gè)節(jié)點(diǎn)發(fā)送像這樣的方法幀時(shí),它總是會(huì)遵循一個(gè)內(nèi)容頭幀(conent header frame)和零個(gè)或多個(gè)內(nèi)容體幀(content body frame)的形式.
一個(gè)內(nèi)容頭幀有下面的格式:

我們將內(nèi)容體放置在不同的幀中(并不包含在方法中),因此AMQP可支持零拷貝技術(shù),這樣其內(nèi)容就不需要編組或編碼. 我們將內(nèi)容屬性安放在它們自己的幀中,以便收件人可以有選擇地丟棄他們不想處理的內(nèi)容。
2.3.5.3 心跳幀
心跳是一種設(shè)計(jì)用來(lái)撤銷(undo)TCP/IP功能的技術(shù),也就是說(shuō)在長(zhǎng)時(shí)間超時(shí)后,它有能力通過(guò)關(guān)閉broker物理連接來(lái)進(jìn)行恢復(fù).在某些情景下,我們需要快速知道節(jié)點(diǎn)連接是否斷開(kāi)了,或者是由于什么原因不能響應(yīng)了.因?yàn)樾奶梢栽谳^低水平上進(jìn)行,我們?cè)趥鬏攲哟紊习垂?jié)點(diǎn)交換的特定幀類型來(lái)處理,而不是按類方法.
2.3.6 錯(cuò)誤處理
AMQP使用異常來(lái)處理錯(cuò)誤.任何操作錯(cuò)誤(未找到消息隊(duì)列,訪問(wèn)權(quán)限不足)都會(huì)導(dǎo)致一個(gè)通道異常. 任何結(jié)構(gòu)化的錯(cuò)誤(無(wú)效參數(shù),壞序列的方法.)都會(huì)導(dǎo)致一個(gè)連接異常.異常會(huì)關(guān)閉通道或連接,同時(shí)也會(huì)向客戶端應(yīng)用返回響應(yīng)碼和響應(yīng)文本.我們使用了類似于HTTP等協(xié)議和其它大多數(shù)協(xié)議中的三位回復(fù)代碼和文字回復(fù)文本方案.
2.3.7 關(guān)閉通道和連接
連接或通道,對(duì)于客戶端來(lái)說(shuō),當(dāng)其發(fā)送Open時(shí)則被認(rèn)為是“打開(kāi)”的,對(duì)于服務(wù)器端來(lái)說(shuō),當(dāng)其發(fā)送Open-Ok時(shí)則被認(rèn)為是打開(kāi)的。基于這一點(diǎn),一個(gè)希望關(guān)閉通道或連接的對(duì)等體也必須使用握手協(xié)議來(lái)這樣做。
可出于任何原因,可能會(huì)正常地或異常地關(guān)閉一個(gè)通道或連接-因此必須仔細(xì)小心。
對(duì)于突然或意外關(guān)閉,并不能得到快速探測(cè),因此當(dāng)發(fā)生異常時(shí),我們可能會(huì)丟失錯(cuò)誤回復(fù)代碼。
正確的設(shè)計(jì)是對(duì)于所有關(guān)閉必須進(jìn)行握手,使我們關(guān)閉后對(duì)方知道相應(yīng)的情況。
當(dāng)一個(gè)節(jié)點(diǎn)決定關(guān)閉一個(gè)通道或連接時(shí),它發(fā)送一個(gè)Close方法。接收節(jié)點(diǎn)必須使用Close-Ok來(lái)響應(yīng)Close,然后雙方可以關(guān)閉他們的通道或連接。請(qǐng)注意,如果節(jié)點(diǎn)忽略了關(guān)閉,當(dāng)兩個(gè)節(jié)點(diǎn)同時(shí)發(fā)送Close時(shí),可能會(huì)發(fā)生死鎖。
2.4 AMQP Client 架構(gòu)
可直接從應(yīng)用程序中讀寫AMQP幀,但這是相當(dāng)糟糕的設(shè)計(jì).
即使是最簡(jiǎn)單的對(duì)話框也比較復(fù)雜(比如同HTTP比較),應(yīng)用程序開(kāi)發(fā)者沒(méi)必要為了向消息隊(duì)列發(fā)送消息, 而來(lái)理解二進(jìn)制這樣的東西. 推薦的AMQP client架構(gòu)須由下面的多個(gè)抽象層組成:
1. 幀層. 此層接受AMQP協(xié)議方法,并按某種語(yǔ)言格式(結(jié)構(gòu),類等等) 來(lái)序列化成線路級(jí)幀.幀層可以根據(jù)AMQP規(guī)范機(jī)械產(chǎn)生(這是在一個(gè)協(xié)議的建模語(yǔ)言,專為AMQP定義了XML實(shí)現(xiàn)).
2. 連接管理層. 此層用于讀寫AMQP幀,并管理所有連接,會(huì)話邏輯.在此層中,我們可以封裝打開(kāi)連接和會(huì)話,錯(cuò)誤處理,內(nèi)容傳輸和接收的全部邏輯. 此層的大部分都可通過(guò)AMQP規(guī)范來(lái)生成.例如,規(guī)范定義了哪些方法可以攜帶內(nèi)容, 因?yàn)檫壿嫲l(fā)送方法和可選的發(fā)送內(nèi)容可以機(jī)械的生成.
3. API 層. 此層暴露了應(yīng)用程序工作的特定API. API層可能會(huì)反映一些現(xiàn)有的標(biāo)準(zhǔn),或暴露高層AMQP的方法,或?qū)Ρ竟?jié)前面介紹的內(nèi)容做一個(gè)映射。AMQP方法設(shè)計(jì)為使這些映射簡(jiǎn)單有用。API層本身可能是由多個(gè)層組成的,如.構(gòu)建于AMQP方法API之上的高級(jí)API.
此外,通常還會(huì)有一些I / O層,這此可以是非常簡(jiǎn)單的(同步套接字讀取和寫入)或復(fù)雜的(完全異步多線程I / O)。此圖顯示了整體推薦的架構(gòu):

在本文檔中,當(dāng)我們說(shuō)"client API"的時(shí)候,我們指的則是應(yīng)用程序下的所有層(i/o,幀,連接按理和API層).我們通常將客戶端API和應(yīng)用程序分開(kāi)說(shuō), 在這里,應(yīng)用程序會(huì)使用客戶端API來(lái)同中間件服務(wù)器進(jìn)行對(duì)話.
3 功能說(shuō)明
3.1 Server 功能說(shuō)明
3.1.1 消息和內(nèi)容
消息是中間件路由和隊(duì)列系統(tǒng)處理的原子單元。消息可攜帶一份內(nèi)容,它包括一個(gè)內(nèi)容頭,一組屬性,和一個(gè)內(nèi)容體,和持有一個(gè)不透明的二進(jìn)制數(shù)據(jù)塊。
一個(gè)消息可以對(duì)應(yīng)到許多不同應(yīng)用程序的實(shí)體:
一個(gè)應(yīng)用程序級(jí)消息
一個(gè)傳輸文件
一個(gè)數(shù)據(jù)流幀等等.
消息可以持久化.一個(gè)持久化消息可以安全地存儲(chǔ)在磁盤上,即使是在嚴(yán)重的網(wǎng)絡(luò)故障,服務(wù)器崩潰、溢出等情況下也可確保投遞.消息也可以有優(yōu)先級(jí).高優(yōu)先級(jí)消息會(huì)在等待同一個(gè)消息隊(duì)列時(shí),在低優(yōu)先級(jí)消息之前發(fā)送. 當(dāng)消息必須被丟棄以確保服務(wù)器質(zhì)量水平,將會(huì)優(yōu)先丟棄低優(yōu)先級(jí)消息.
服務(wù)器不能修改接收到并將傳遞給消費(fèi)者應(yīng)用程序的消息內(nèi)容體. 服務(wù)器可在內(nèi)容頭中添加額外信息,但不能刪除或修改現(xiàn)有信息.
3.1.2 虛擬主機(jī)(Virtual Hosts)
虛擬主機(jī)是服務(wù)器內(nèi)的數(shù)據(jù)分區(qū), 它為在共享基礎(chǔ)設(shè)施上的管理帶來(lái)了方便.
一個(gè)虛擬主機(jī)包括其命名空間,一組交換器,消息隊(duì)列以及所有相關(guān)對(duì)象. 每個(gè)連接必須關(guān)聯(lián)一個(gè)單個(gè)虛擬主機(jī).
在認(rèn)證后,客戶端可在Connection.Open方法中選擇虛擬主機(jī). 這意味著,服務(wù)器上的認(rèn)證方案可在此服務(wù)器上的所有虛擬主機(jī)上共享. 然而,對(duì)于每個(gè)虛擬主機(jī)來(lái)說(shuō),也可以獨(dú)特的認(rèn)證方案. 對(duì)于每個(gè)虛擬主機(jī)需要不同的身份驗(yàn)證方案的管理員應(yīng)該使用單獨(dú)的服務(wù)器。
連接中的所有通道都在同一個(gè)虛擬主機(jī)上工作.在同一個(gè)連接中,沒(méi)有與不同虛擬主機(jī)通信的方式, 也沒(méi)有在不斷開(kāi)連接重新開(kāi)始的情況下,切換到其它虛擬主機(jī)的可能性.
該協(xié)議沒(méi)有提供用于創(chuàng)建或配置虛擬主機(jī)的機(jī)制-這在服務(wù)器內(nèi)是一個(gè)不確定的方式,是完全依賴于實(shí)現(xiàn)的。
3.1.3 交換器
交換器是一個(gè)虛擬主機(jī)內(nèi)的消息路由代理。交換器實(shí)例(我們通常稱之為“交換器”)接受消息和路由信息-主要是一個(gè)路由鍵-或者將消息傳遞到消息隊(duì)列,或到內(nèi)部服務(wù)。交換器是基于每個(gè)虛擬主機(jī)命名的。
應(yīng)用程序可以在權(quán)限范圍內(nèi)自由地創(chuàng)建、共享、使用和銷毀交換器實(shí)例.交換器可能是持久的、臨時(shí)的或自動(dòng)刪除的。持久化的交換器會(huì)持續(xù)到他們被刪除,臨時(shí)的交換器會(huì)持續(xù)到服務(wù)器關(guān)閉。自動(dòng)刪除的交換器直到他們不再使用。服務(wù)器提供了一組特定的交換器類型。每個(gè)交換器類型都實(shí)現(xiàn)了一個(gè)特定的匹配和算法,如下一節(jié)中定義的。AMQP只要求少量的交換器類型,并推薦了一些。此外,每個(gè)服務(wù)器實(shí)現(xiàn)可以添加自己的交換類型。
交換器可以將單個(gè)消息并發(fā)地路由到的消息隊(duì)列中。這將創(chuàng)建一個(gè)獨(dú)立消息的多個(gè)實(shí)例。
3.1.3.1 Direct交換器類型
direct 交換器按如下方式來(lái)工作:
1. 消息隊(duì)列使用路由鍵K來(lái)綁定交換器.
2. 發(fā)布者使用路由鍵R來(lái)向交換器發(fā)送消息.
3. 在K=R時(shí),消息會(huì)傳遞到消息隊(duì)列中.
server必須實(shí)現(xiàn)direct交換器,并且在每個(gè)虛擬主機(jī)中必須預(yù)定義兩個(gè)direct交換器: 一個(gè)名為 amq.direct, 另一個(gè)無(wú)公共名稱(為Publish方法的默認(rèn)交換器).
注意,消息隊(duì)列可以使用任何有效的路由鍵值進(jìn)行綁定,但通常消息隊(duì)列使用它們自己的名稱作路由鍵來(lái)綁定.
事實(shí)上,所有消息隊(duì)列必須能使用其自身隊(duì)列名稱作路由鍵自動(dòng)綁定無(wú)名稱的交換器上.
3.1.3.2 Fanout 交換器類型
fanout交換器類型按如下方式來(lái)工作:
1. 消息隊(duì)列不使用參數(shù)來(lái)綁定交換器.
2. 發(fā)布者向交換器發(fā)送消息.
3. 消息無(wú)條件傳遞給消息隊(duì)列。
fanout 交換器是微不足道的設(shè)計(jì)與實(shí)現(xiàn).此交換器類型和預(yù)聲明的交換器稱為amq.fanout,它是強(qiáng)制的.
3.1.3.3 Topic交換器類型
topic交換器類型按如下方式來(lái)工作:
1. 消息隊(duì)列使用路由模式P來(lái)綁定到交換器.
2. 發(fā)布者使用路由鍵R來(lái)向交換器發(fā)送消息.
3. 當(dāng)R匹配P時(shí),消息將被傳遞到消息隊(duì)列.
用于topic交換器的路由鍵必須由0個(gè)或多個(gè)由點(diǎn)號(hào)
用于topic交換器的路由鍵必須由點(diǎn)分隔的零或多個(gè)單詞組成.每個(gè)單詞必須包含字母A-Z和a-z 以及數(shù)字0-9.
路由模式與路由鍵遵循相同的規(guī)則,* 用于匹配單個(gè)單詞,# 用于匹配0個(gè)或多個(gè)單詞.因此路由模式*.stock.# 會(huì)匹配路由鍵usd.stock 和eur.stock.db 但不匹配stock.nasdaq.
對(duì)于topic交換器我們建議的設(shè)計(jì)是保持所有已知路由鍵的集合,當(dāng)發(fā)布者使用了新的路由鍵時(shí),才更新此集合. 通過(guò)給定一個(gè)路由鍵來(lái)確實(shí)所有綁定是可能的,因此可為消息快速找到消息隊(duì)列. 此交換器類型是可選的.
server應(yīng)該實(shí)現(xiàn)topic交換器類型,在這種情況下,server 必須在每個(gè)虛擬主機(jī)中預(yù)先定義至少一個(gè) topic交換器,其名稱為amq.topic.
3.1.3.4 Headers交換器類型
headers交換器類型按如下方式進(jìn)行工作:
1. 消息隊(duì)列使用包含匹配綁定和帶有默認(rèn)值的header參數(shù)表來(lái)綁定交換器.在這種交換器類型中,不使用路由鍵.
2.發(fā)布者向交換器發(fā)送消息,這些消息的headers屬性中包含名稱-值對(duì)的表.
3.如果消息頭屬性與隊(duì)列綁定的參數(shù)相匹配,則消息傳遞給隊(duì)列。
匹配算法是由參數(shù)表中的名稱值對(duì)這樣的特殊綁定參數(shù)來(lái)控制的. 這個(gè)參數(shù)的名稱是'x-match'.
它可以接受兩種值, 以表示表格中其它的名稱值對(duì)將如何來(lái)進(jìn)行匹配:
'all' 則表明所有其它的名稱值對(duì)必須與路由消息的頭屬性相匹配(即.AND匹配)
'any' 則表明只要消息頭屬性中的任何一個(gè)字段匹配參數(shù)表中的字段,則消息就應(yīng)該被路由(即. OR匹配).
綁定參數(shù)中的字段必須與消息字段中的字段相匹配,這些情況包括:如果綁定參數(shù)中的字段沒(méi)有值且在消息頭中存在相同名稱的字段,或者綁定參數(shù)中的字段有值,且消息屬性中存在同樣的字段且有相同的值。
任何以'x-'而不是'x-match'開(kāi)頭的字段為將來(lái)保留使用并會(huì)被忽略.
server應(yīng)該實(shí)現(xiàn)headers交換器類型, 且server必須在每個(gè)虛擬主機(jī)中預(yù)先聲明至少一個(gè)headers交換器,且名稱為amq.match.
3.1.3.5 System交換器類型
system交換器類型按如下方式進(jìn)行工作:
1. 發(fā)布者使用路由鍵S來(lái)向交換器發(fā)送消息.
2. system交換器將其傳遞給系統(tǒng)服務(wù)S.
系統(tǒng)服務(wù)以"amq."開(kāi)頭,為AMQP保留使用. 在服務(wù)器環(huán)境中,所有其它名稱可自由使用. 此交換器類型是可選的.
3.1.3.6 實(shí)現(xiàn)定義的交換器類型
所有非規(guī)范交換器類型必須以"x-"開(kāi)頭. 不以"x-"開(kāi)頭的交換器作為將來(lái)AMQP標(biāo)準(zhǔn)保留使用.
3.1.4 消息隊(duì)列
消息隊(duì)列是一個(gè)名為FIFO的緩沖區(qū)且為一組消費(fèi)者應(yīng)用程序保存消息.
在其權(quán)限范圍內(nèi),應(yīng)用程序可以自由地創(chuàng)建、共享、使用和銷毀消息隊(duì)列.
注意,在一個(gè)隊(duì)列中可能存在多個(gè)讀者,或存在客戶端事務(wù),或存在使用了優(yōu)先級(jí)字段,或存在使用了消息選擇器,或特定實(shí)現(xiàn)了投遞優(yōu)化的隊(duì)列可能不會(huì)真正地展現(xiàn)出FIFO特性. 唯一可以確保FIFO的方式是只有一個(gè)消費(fèi)者連上了隊(duì)列.在那些情況下,隊(duì)列可描述為弱-FIFO.
消息隊(duì)列可能是持久化的或自動(dòng)刪除的.持久化消息隊(duì)列會(huì)持續(xù)到它們刪除時(shí)為止. 臨時(shí)消息隊(duì)列可持續(xù)到服務(wù)器關(guān)閉時(shí)為止.自動(dòng)刪除消息隊(duì)列可持續(xù)到它們不再使用時(shí)為止.
Message隊(duì)列可將消息存儲(chǔ)在內(nèi)存,磁盤,或兩者的組合中.消息隊(duì)列是基于虛擬主機(jī)來(lái)命名的.
消息隊(duì)列保存信息,并可在一個(gè)或多個(gè)消費(fèi)客戶端之間進(jìn)行分發(fā).路由到消息隊(duì)列中的消息不能再發(fā)給多個(gè)客戶端,除非在失敗或拒絕后進(jìn)行重發(fā).
單個(gè)消息隊(duì)列可在同個(gè)時(shí)間可獨(dú)立地持有不同類型的內(nèi)容.也就是,如果Basic和文件內(nèi)容都發(fā)給了同一個(gè)消息隊(duì)列,這些將會(huì)作為請(qǐng)求獨(dú)立地分發(fā)給消費(fèi)應(yīng)用程序.
3.1.5 綁定
綁定是消息隊(duì)列和交換器之間的關(guān)系.綁定特有的路由參數(shù)將告訴交換器那些隊(duì)列應(yīng)該得到消息. 應(yīng)用程序可根據(jù)需要來(lái)驅(qū)動(dòng)消息流向它們的消息隊(duì)列. 綁定的壽命依賴于定義它們的消息隊(duì)列 - 當(dāng)消息隊(duì)列被銷毀時(shí),其綁定也會(huì)被銷毀.Queue.Bind 方法的特定語(yǔ)義將依賴于交換器類型.
3.1.6 消費(fèi)者
我們使用術(shù)語(yǔ)"consumer"來(lái)表示應(yīng)用程序和控制客戶端程序來(lái)接收消息隊(duì)列中的實(shí)體.當(dāng)客戶端啟動(dòng)一個(gè)消費(fèi)者,它就在服務(wù)器中創(chuàng)建了一個(gè)消費(fèi)實(shí)體 .當(dāng)客戶端退出一個(gè)消費(fèi)者時(shí),它就銷毀了一個(gè)服務(wù)器中的消費(fèi)者實(shí)體. 屬于單個(gè)客戶端通道的消費(fèi)者可異步地將消息發(fā)送到隊(duì)列中.
3.1.7 服務(wù)質(zhì)量
服務(wù)質(zhì)量控制了消息發(fā)送的速度. 服務(wù)質(zhì)量依賴于被分發(fā)的內(nèi)容類型.一般的服務(wù)質(zhì)量,在客戶端應(yīng)答消息前,會(huì)使用預(yù)提取的概念來(lái)指定發(fā)送多少個(gè)消息或多少個(gè)字節(jié)的數(shù)量. 目標(biāo)是提前發(fā)送消息數(shù)據(jù),以減少延遲。
3.1.8 確認(rèn)/應(yīng)答
應(yīng)答是從客戶端程序發(fā)出的正式信號(hào),用以表示消息隊(duì)列中的消息已經(jīng)得到成功處理. 有兩種應(yīng)答模型:
1. 自動(dòng)地(Automatic), 在這種情況下,只要消息投遞到了應(yīng)用程序,服務(wù)器就會(huì)立即從消息隊(duì)列中刪除消息(通過(guò) Deliver 或 Get-Ok 方法).
2. 明確地(Explicit),在這種情況下,客戶端程序必須對(duì)每個(gè)消息發(fā)磅一個(gè)Ack方法以表示消息被處理了.客戶端層可以不同方式來(lái)實(shí)現(xiàn)明確應(yīng)答,如.只要收到了消息或當(dāng)應(yīng)用程序表示消息已經(jīng)處理了.
這些區(qū)別不會(huì)影響AMQP或互操作性.
3.1.9 流控制(Flow Control)
流控制是一個(gè)用來(lái)中止節(jié)點(diǎn)消息流的緊急過(guò)程. 它在客戶端和服務(wù)器端都按同樣方式工作,且都是由Channel.Flow命令實(shí)現(xiàn)的. 流控制是唯一可以阻止一個(gè)過(guò)度生產(chǎn)發(fā)布者的機(jī)制.如果它使用消息確認(rèn)(這通常意味著使用事務(wù)), 消費(fèi)者則可以使用更優(yōu)雅的預(yù)取機(jī)制窗口。
3.1.10 命名約定
這些約定規(guī)范了AMQP實(shí)體命名. 服務(wù)器和客戶端必須遵守這些約定:
用戶定義的交換器類型前輟必須是"x-"
標(biāo)準(zhǔn)交換器實(shí)例前輟是"amq."
標(biāo)準(zhǔn)系統(tǒng)服務(wù)前輟是"amq."
標(biāo)準(zhǔn)消息隊(duì)列前輟是"amq."
所有其他的交換器、系統(tǒng)服務(wù)和消息隊(duì)列名稱都在應(yīng)用程序空間中。
3.2 AMQP 命令說(shuō)明(Classes & Methods)
3.2.1 解釋性注釋
出于互操作原因,AMQP方法可以定義特定的最小值(如每消息隊(duì)列的消費(fèi)者數(shù)量)。這些極小值被定義在每個(gè)類的描述中。
遵從AMQP的實(shí)現(xiàn)應(yīng)該為這些字段實(shí)現(xiàn)合理值, 最小值只用在最小能力的平臺(tái)上.
語(yǔ)法使用這樣的標(biāo)記法:
'S:' 指示從服務(wù)器發(fā)送到客戶端的數(shù)據(jù)或方法;
'C:' 指示從客戶端發(fā)送到服務(wù)器的數(shù)據(jù)或方法;
+term or +(...) 表達(dá)式表示1個(gè)或多個(gè)實(shí)例;
*term or *(...) 表達(dá)式表示0個(gè)或多個(gè)實(shí)例.
我們定義的方法是:
一個(gè)同步請(qǐng)求("syn request").發(fā)送節(jié)點(diǎn)應(yīng)該等待特定的回復(fù)方法,但可以異步實(shí)現(xiàn)此方法;
一個(gè)同步回復(fù)("syn reply for XYZ");
一個(gè)異步請(qǐng)求或答復(fù) ("async").
3.2.2 類和方法細(xì)節(jié)
這部分是由生成的文件amqp-xml-spec.odt提供。
4 技術(shù)說(shuō)明
4.1 IANA分配的端口號(hào)
IANA為標(biāo)準(zhǔn)AMQP的TCP和UDP分配了5672端口。UDP端口被保留用于將來(lái)的組播實(shí)現(xiàn)。
4.2 AMQP 線程級(jí)格式
4.2.1 正式協(xié)議語(yǔ)法
我們?yōu)锳MQP提供了一個(gè)完整語(yǔ)法(這只是AMQP提供的參考,跳到下一節(jié),你會(huì)發(fā)現(xiàn)不同的幀類型和格式):


我們使用了IETF RFC 2234中定義的增強(qiáng)BNF語(yǔ)法. 總體而言,
規(guī)則的名稱僅僅是名稱本身。
終端是由一個(gè)或多個(gè)數(shù)字字符指定的,這些字符的基本解釋為“d”或“x”。
通過(guò)列出一系列規(guī)則名稱,一個(gè)規(guī)則可以定義一個(gè)簡(jiǎn)單的,有序的字符串的值.
其他數(shù)值的范圍可以簡(jiǎn)潔指定,使用破折號(hào)(“-”)來(lái)表示替代值的范圍。
在圓括號(hào)中的元素被視為單個(gè)元素,其內(nèi)容是嚴(yán)格有序的。
由/分隔的元素是可替代值.
元素之間的操作符 "*"表示重復(fù).完整格式為: "<a>*<b>element",這里<a>的<b>是可選的十進(jìn)制值, 表示只能出現(xiàn)大于<a>而小于<b>的元素.
規(guī)則形式: "<n>element" 等價(jià)于<n>*<n>element.
方括號(hào)中的元素是可選元素.
4.2.2 協(xié)議頭
client必須通常發(fā)送一個(gè)協(xié)議頭開(kāi)始新連接.它是8字節(jié)序列:

協(xié)議頭由大寫字母"AMQP",其后跟常量%d0組成:
1. 協(xié)議主版本號(hào), 按照章節(jié)1.4.2中描述的使用.
2. 協(xié)議次版本號(hào), 按照章節(jié)1.4.2中描述的使用.
3. 協(xié)議修訂版本, 按照章節(jié)1.4.2中描述的使用.
該協(xié)議協(xié)商模型與現(xiàn)有HTTP協(xié)議兼容,使用常量文本字符串來(lái)發(fā)起連接, 并使用防火墻來(lái)檢測(cè)協(xié)議的開(kāi)始以決定應(yīng)用什么規(guī)則.
client和服務(wù)通過(guò)以下方式來(lái)達(dá)成協(xié)議版本一致:
client打開(kāi)一個(gè)到AMQP服務(wù)器的新socket連接,并發(fā)送協(xié)議頭.
server可接受或拒絕協(xié)議頭.如果它拒絕了協(xié)議頭,它將會(huì)輸出一個(gè)有效的協(xié)議頭到socket,然后再關(guān)閉socket.
否則它會(huì)同意(leaves)socket打開(kāi),并相應(yīng)地實(shí)現(xiàn)協(xié)議.
示例:

實(shí)現(xiàn)者指導(dǎo)方針:
server可接受非AMQP協(xié)議,如HTTP.
如果server無(wú)法識(shí)別socket數(shù)據(jù)中的前5個(gè)字節(jié),或者它不支持client請(qǐng)求的協(xié)議版本,它必須輸出一個(gè)有效的協(xié)議頭到socket,然后再關(guān)閉socket (必須確保client應(yīng)用程序能收到數(shù)據(jù)) ,最后再關(guān)閉socket連接.服務(wù)器可以打印診斷信息以輔助調(diào)試。
client可使用服務(wù)器支持的最高版本來(lái)進(jìn)行檢測(cè),如果收到了服務(wù)器發(fā)回的這種信息,就可使用較低版本來(lái)進(jìn)行重連
實(shí)現(xiàn)了多版本AMQ的Clients和servers都應(yīng)該使用8字節(jié)的協(xié)議頭來(lái)標(biāo)識(shí)協(xié)議.
4.2.3 通用幀格式
所有幀都以7個(gè)字節(jié)的頭開(kāi)始,其中包括一個(gè)type字段 ,一個(gè)channel字段和一個(gè)size字段:

AMQP 定義了如下的幀類型:
Type = 1, "METHOD": 方法幀
Type = 2, "HEADER": 內(nèi)容頭幀
Type = 3, "BODY": 內(nèi)容體幀.
Type = 4, "HEARTBEAT": 心跳幀.
通道編號(hào)為0的代表全局連接中的所有幀,1-65535代表特定通道的幀.
size字段是負(fù)載的大小,不包括結(jié)束幀字節(jié). 由于AMQP假設(shè)是一個(gè)可靠的連接協(xié)議,我們使用結(jié)束幀來(lái)檢測(cè)錯(cuò)誤客戶端和服務(wù)器實(shí)現(xiàn)引起的錯(cuò)誤.
實(shí)現(xiàn)者指導(dǎo)方針:
結(jié)束幀必須是十六進(jìn)制值%xCE.
如果一個(gè)節(jié)點(diǎn)收到了未定義類型的幀,它必須將其視為致命的協(xié)議錯(cuò)誤,并關(guān)閉連接,而不進(jìn)一步地發(fā)送任何數(shù)據(jù)
當(dāng)一個(gè)節(jié)點(diǎn)讀取到幀時(shí),在解碼幀前,它必須檢查結(jié)束幀是否是有效的. 如果結(jié)束幀無(wú)效,它必須將其視為致使的協(xié)議錯(cuò)誤,并關(guān)閉連接,而不進(jìn)一步地發(fā)送任何數(shù)據(jù). 它應(yīng)該記錄相關(guān)問(wèn)題的日志信息,這樣就可以服務(wù)器或客戶端幀代碼實(shí)現(xiàn)中表示錯(cuò)誤.
節(jié)點(diǎn)發(fā)送的幀大小不能超過(guò)約定的大小. 節(jié)點(diǎn)收到超過(guò)大小的幀時(shí),必須發(fā)出一個(gè)回復(fù)碼為501(幀錯(cuò)誤)的連接異常信號(hào).
對(duì)于所有心跳幀,方法幀,連接類的頭和體,通道編號(hào)必須為0. 節(jié)點(diǎn)收到非0通道編號(hào)的這些幀必須使用回復(fù)碼503(無(wú)效命令)來(lái)發(fā)出異常信號(hào).
4.2.4 方法負(fù)載
方法幀的體包括一個(gè)不可變的數(shù)據(jù)字段列表,稱為"arguments".所有方法體都以類型和方法的標(biāo)識(shí)符開(kāi)始:

實(shí)現(xiàn)者指導(dǎo)方針:
class-id 和 method-id是由AMQP類和方法定義的常量.
arguments 是特定于每個(gè)方法中的一組AMQP字段.
Class id 中%x00.01-%xEF.FF范圍內(nèi)的值被AMQP標(biāo)準(zhǔn)類保留使用.
Class id 中%xF0.00-%xFF.FF (%d61440-%d65535) 范圍內(nèi)的值可用于非標(biāo)準(zhǔn)擴(kuò)展類實(shí)現(xiàn).
4.2.5 AMQP 數(shù)據(jù)字段
AMQP有兩種級(jí)別的數(shù)據(jù)字段:用于方法參數(shù)的原生數(shù)據(jù)字段, 以及用于多個(gè)應(yīng)用之間傳遞數(shù)據(jù)的字段表. 字段表是原生數(shù)據(jù)字段的超集.
4.2.5.1 Integers
AMQP定義了這些原生整數(shù)類型:
無(wú)符號(hào)字節(jié)(8 bits).
無(wú)稱號(hào)短整形(16 bits).
無(wú)符號(hào)長(zhǎng)整形(32 bits).
無(wú)符號(hào)長(zhǎng)長(zhǎng)整形(64 bits).
整形和字符串長(zhǎng)度總是無(wú)符號(hào)的,且按網(wǎng)絡(luò)字節(jié)順序保存. 當(dāng)存在兩個(gè)高低系統(tǒng)時(shí)(如.兩個(gè)Intel CPUS),我們不會(huì)對(duì)它們的交互嘗試優(yōu)化.
實(shí)現(xiàn)方針:
實(shí)現(xiàn)不能假設(shè)幀內(nèi)的整形編碼在內(nèi)存邊界中是對(duì)齊的.
4.2.5.2 Bits
AMQP定義了一個(gè)原生位字段類型. 位累積成整個(gè)字節(jié). 當(dāng)在幀中兩個(gè)或更多位相鄰時(shí),它們會(huì)被包裝成一個(gè)或多個(gè)字節(jié),且在每個(gè)字節(jié)中以低位開(kāi)始.
沒(méi)有要求在一個(gè)幀中的所有位必須是連續(xù)的,但這通常是做,以盡量減少幀尺寸。
4.2.5.3 Strings
AMQP 字符串是可變長(zhǎng)度,由一個(gè)整數(shù)長(zhǎng)度后跟零個(gè)或多個(gè)字節(jié)數(shù)據(jù)表示. AMQP定義了兩種原生字符串類型:
短字符串(Short strings),以8位無(wú)稱號(hào)整形長(zhǎng)度后跟0個(gè)或多個(gè)字節(jié)數(shù)據(jù)存儲(chǔ). 短字符串可攜帶最多255字節(jié)的UTF-8數(shù)據(jù), 但不能包含二進(jìn)制零字節(jié).
長(zhǎng)字符串(Long strings), 以32位無(wú)稱號(hào)整形長(zhǎng)度后跟0個(gè)或多個(gè)字節(jié)數(shù)據(jù)存儲(chǔ). 長(zhǎng)字符串可包含任意數(shù)據(jù).
4.2.5.4 時(shí)間戳(Timestamps)
時(shí)間戳是以精度為1秒的64位POSIX time_t 格式保存的.使用64伴可以避免31位和32位相關(guān)的time_t值概括問(wèn)題(wraparound issues).
4.2.5.5 字段表
字段表是包含名稱-值對(duì)的長(zhǎng)字符串. 名稱-值對(duì)編碼為:以短字符串定義名稱,字節(jié)定義值類型和值. 有效的表字段類型是原生整形,位,字符串,時(shí)間戳類型的擴(kuò)展. 多字節(jié)整形字段通常是按網(wǎng)絡(luò)字節(jié)順序保存的.
指導(dǎo)方針:
字段名稱必須以字母開(kāi)頭,其后可跟'$,'#',數(shù)字,下劃線,最大長(zhǎng)度為128個(gè)字符.
server應(yīng)該驗(yàn)證字段名稱,如果收到了無(wú)效的字段名稱,它應(yīng)該使用回復(fù)碼503(語(yǔ)法錯(cuò)誤)來(lái)發(fā)出異常信號(hào).
十進(jìn)制值不用于支持浮點(diǎn)值,它是固定的業(yè)務(wù)值,如貨幣匯率和金額。其字節(jié)編碼代表了位置編號(hào),其后跟著一個(gè)無(wú)符號(hào)的長(zhǎng)整數(shù).“十進(jìn)制”是無(wú)符號(hào)的.
重復(fù)字段是非法的。對(duì)于一個(gè)包含重復(fù)字段的表,其行為是未定義的。
4.2.6 內(nèi)容幀
某些特定的方法(Publish, Deliver, etc.) 會(huì)攜帶內(nèi)容.請(qǐng)參考 "Functional Specifications" 來(lái)了解每種方法的說(shuō)明,以及它們是否是攜帶內(nèi)容的方法.
內(nèi)容由1個(gè)或多個(gè)幀組成:
1. 只有一個(gè)內(nèi)容頭幀能提供內(nèi)容屬性.
2. 可選的, 可以有1個(gè)或多個(gè)內(nèi)容體幀.
特定通道上的內(nèi)容幀是嚴(yán)格有序的. 也就是說(shuō),它們可以和其它通道的幀混合,但同一個(gè)通道內(nèi)兩個(gè)幀是不可能混合或重疊, 也不可能出現(xiàn)單個(gè)內(nèi)容上的內(nèi)容幀與相同通道上的方法幀相混合.
注意,任何非內(nèi)容幀都會(huì)明確地標(biāo)識(shí)內(nèi)容的結(jié)束. 盡管可從內(nèi)容頭中知道內(nèi)容的大小,但也允許發(fā)送者在不關(guān)閉通道的情況下中止內(nèi)容發(fā)送.
實(shí)現(xiàn)者指導(dǎo)方針:
收到不完整或錯(cuò)誤格式內(nèi)容的節(jié)點(diǎn)必須使用回復(fù)碼500(非希望幀)拋出一個(gè)連接異常. 這包括缺少內(nèi)容頭,內(nèi)容頭中錯(cuò)誤的class IDs,缺少內(nèi)容體幀等等.
4.2.6.1 內(nèi)容頭
內(nèi)容頭負(fù)載有下面的格式:

實(shí)現(xiàn)者指導(dǎo)方針:
class-id必須與方法幀class id匹配. 節(jié)點(diǎn)必須對(duì)無(wú)效的class-id使用501回復(fù)碼(幀錯(cuò)誤)拋出一個(gè)連接異常.
weight字段未使用且必須是0.
body大小是一個(gè)64位值,它定義了內(nèi)容體的總大小,也就是后面內(nèi)容體幀的body大小的總和. 0表示無(wú)內(nèi)容體幀.
property flags是位數(shù)組,它表示每個(gè)屬性的存在性. 位是從最高到最低進(jìn)行排序的,位15代表第一個(gè)屬性.
property flags可指定多于16屬性.如果最后位(0)被設(shè)置了,這表明其后有進(jìn)一步的屬性標(biāo)志字段。根據(jù)需要,這里有許多屬性標(biāo)志字段。
屬性值是特定類的AMQP數(shù)據(jù)字段.
位屬性僅由它們各自的屬性標(biāo)志(0或1)表示,并且在屬性列表中不存在。
內(nèi)容幀中的通道編碼不能為0.在內(nèi)容幀中收到0通道編號(hào)的節(jié)點(diǎn)必須使用504回復(fù)碼(通道錯(cuò)誤)來(lái)發(fā)出異常信號(hào)
4.2.6.2 內(nèi)容體
內(nèi)容體負(fù)載是是不透明的二進(jìn)制塊,其后跟著一個(gè)結(jié)束幀字節(jié):

內(nèi)容體可以根據(jù)需要分成多個(gè)幀.幀負(fù)載的最大大小可在連接時(shí),由兩端進(jìn)行協(xié)商.
實(shí)現(xiàn)者指導(dǎo)方針:
節(jié)點(diǎn)必須要能將分成多個(gè)幀的內(nèi)容體作為單一集合進(jìn)行存儲(chǔ)處理,要么分成更小的幀重新傳輸,要么 連接成單個(gè)塊分發(fā)給應(yīng)用程序.
4.2.7 心跳幀
心跳幀告訴收件人發(fā)件人仍然是活的. 在連接時(shí),心跳幀的速率和時(shí)間都可以調(diào)整.
實(shí)現(xiàn)者指導(dǎo)方針:
心跳幀的通道編號(hào)必須為0. 收到無(wú)效心跳幀的節(jié)點(diǎn)需使用501回復(fù)碼(幀錯(cuò)誤)來(lái)拋出異常.
如果節(jié)點(diǎn)不支持心跳,它必須在不發(fā)出錯(cuò)誤或失敗信號(hào)的情況下丟棄心跳幀.
client收到Connection.Tune方法后,必須要開(kāi)始發(fā)送心跳, 并在收到Connection.Open后,必須要開(kāi)始監(jiān)控.server在收到Connection.Tune-Ok后,需要開(kāi)始發(fā)送和監(jiān)控心跳.
節(jié)點(diǎn)應(yīng)該盡最大努力按固定頻率來(lái)發(fā)送心跳. 心跳可在任何時(shí)候發(fā)送. 任何發(fā)送字節(jié)都可作為心跳的有效替代,因此當(dāng)超過(guò)固定頻率還沒(méi)有發(fā)送非AMQP心跳時(shí),必須發(fā)送心跳.如果節(jié)點(diǎn)在兩個(gè)心跳間隔或更長(zhǎng)時(shí)間內(nèi),未探測(cè)到傳入的心跳,它可在不遵循Connection.Close/Close-Ok握手的情況下,關(guān)閉連接,并記錄錯(cuò)誤信息.
心跳應(yīng)該具有持續(xù)性,除非socket連接已經(jīng)被關(guān)閉, 包括在Connection.Close/Close-Ok 握手期間或之后的時(shí)間.
4.3 通道復(fù)用
AMQP 允許節(jié)點(diǎn)創(chuàng)建多個(gè)獨(dú)立的控制線程.每個(gè)通道都可作為共享單個(gè)socket的虛擬連接:

實(shí)現(xiàn)者指導(dǎo)方針:
AMQP節(jié)點(diǎn)可支持多個(gè)通道.在連接協(xié)商期間,可定義最大通道數(shù)目,節(jié)點(diǎn)可協(xié)商這個(gè)數(shù)值為1.
每個(gè)節(jié)點(diǎn)都應(yīng)該以公平的方式平衡所有打開(kāi)通道的流量. 這種平衡可以每幀為基礎(chǔ),也可以以每個(gè)通道上的總交通流量為基礎(chǔ). 節(jié)點(diǎn)不應(yīng)該允許一個(gè)非常繁忙的通道讓一個(gè)不太繁忙的通道餓死.
4.4 可見(jiàn)性保證
服務(wù)器必須確保客戶端對(duì)服務(wù)器狀態(tài)的觀察是一致的。
下面的示例說(shuō)明了在這種情況下,客戶端的觀察方法:
Client 1 和 Client 2 連上了同一個(gè)虛擬主機(jī)
Client 1 聲明了一個(gè)隊(duì)列
Client 1 收到了Declare.Ok回復(fù) (觀察”的一個(gè)例子)
Client 1 將其告知了Client 2
Client 2 對(duì)同一個(gè)隊(duì)列做了被動(dòng)聲明
可見(jiàn)性必須保證Client 2能看到隊(duì)列(在沒(méi)有刪除的情況下)
4.5 通道關(guān)閉
當(dāng)發(fā)生以下事件時(shí),server會(huì)考慮通道已經(jīng)關(guān)閉了:
1. 節(jié)點(diǎn)關(guān)閉了通道或其父連接使用了Close/Close-Ok握手.
2. 節(jié)點(diǎn)在通道或父連接上拋出了異常.
3.節(jié)點(diǎn)未使用 Close/Close-Ok握手關(guān)閉了父連接socket.
當(dāng)服務(wù)器關(guān)閉通道時(shí),通道上任何未應(yīng)答的消息將標(biāo)記為重新分發(fā).
當(dāng)服務(wù)器關(guān)閉連接時(shí),它會(huì)刪除連接所擁有的自動(dòng)刪除信息.
4.6 內(nèi)容同步
在某些情況下,同步請(qǐng)求響應(yīng)方法會(huì)對(duì)同一個(gè)信道上的異步內(nèi)容傳遞產(chǎn)生影響,包括:
Basic.Consume 和 Basic.Cancel 方法, 這些會(huì)啟動(dòng)和停止消息隊(duì)列中的消息流.
Basic.Recover 方法,它會(huì)要求服務(wù)器重新分發(fā)消息到通道.
Queue.Bind, Queue.Unbind, 和Queue.Purge 方法, 它會(huì)影響消息進(jìn)入消息隊(duì)列.
實(shí)現(xiàn)者指導(dǎo)方針:
請(qǐng)求-響應(yīng)效果在response方法之前必須不可見(jiàn),但在之后必須可見(jiàn).
4.7 內(nèi)容排序保證
流經(jīng)通道的方法順序是穩(wěn)定的:方法按發(fā)送時(shí)的順序接收. 這是由AMQP使用的TCP/IP傳輸所保證的.
此外,服務(wù)器也會(huì)按一種穩(wěn)定的方式來(lái)處理內(nèi)容.尤其是,經(jīng)過(guò)服務(wù)器中單個(gè)路徑的內(nèi)容會(huì)保持順序.
對(duì)于設(shè)定了優(yōu)先級(jí)并經(jīng)過(guò)單個(gè)路徑內(nèi)容,我們定義了一個(gè)內(nèi)容處理路徑-由一個(gè)傳入通道,一個(gè)交換器,一個(gè)隊(duì)列和一個(gè)傳出通道組成.
實(shí)現(xiàn)者指導(dǎo)方針:
server必須保持流經(jīng)單個(gè)內(nèi)容處理路徑上的順序性,除非在Basic.Deliver或Basic.Get-Ok方法上設(shè)置了redelivered字段,可根據(jù)條件規(guī)則來(lái)設(shè)置字段.
4.8 錯(cuò)誤處理
4.8.1 異常
使用標(biāo)準(zhǔn)的異常編程模型, AMQP不會(huì)發(fā)出成功信號(hào),只在失敗時(shí)才發(fā)出信號(hào). AMQP定義了兩種異常級(jí)別:
1. 通道異常.指那些關(guān)閉通道引起的錯(cuò)誤.通道異常通常是因?yàn)檐涘e(cuò)誤引起的,這些錯(cuò)誤并不影響應(yīng)用程序的其它部分.
2. 連接異常. 這些關(guān)閉socket連接的異常通常是因?yàn)橛插e(cuò)誤造成的,如程序錯(cuò)誤,錯(cuò)誤配置或其他需要干預(yù)的情況。
4.8.2 回復(fù)代碼格式
AMQP 回復(fù)代碼按照 IETF RFC 2821的回復(fù)代碼的嚴(yán)重程度和理論進(jìn)行定義.
4.9 限制
AMQP規(guī)范為將來(lái)的AMQP擴(kuò)展或同種線路級(jí)格式使用了如下限制:
每個(gè)連接上的通道數(shù)量: 16位通道數(shù)量.
協(xié)議類數(shù)量: 16位class id.
每個(gè)協(xié)議內(nèi)的方法數(shù)量: 16位 method id.
AMQP規(guī)范對(duì)于數(shù)據(jù)做了如下限制:
短字符串的最大長(zhǎng)度為: 255字節(jié).
長(zhǎng)字符串或字段表的最大長(zhǎng)度: 32位大小.
幀負(fù)載的最大大小: 32位大小
內(nèi)容的最大長(zhǎng)度: 64位大小.
服務(wù)器或客戶端也可以對(duì)資源施加自己的限制,如并發(fā)連接的數(shù)量、每個(gè)通道的消費(fèi)者數(shù)量、隊(duì)列的數(shù)量等。這些不影響互操作性,因此并沒(méi)有指定。
4.10 安全
4.10.1 目標(biāo)和原則
為了防止緩沖區(qū)溢出,我們?cè)谒械胤蕉际褂锰囟ㄩL(zhǎng)度的緩沖區(qū). 當(dāng)讀取數(shù)據(jù)時(shí),所有數(shù)據(jù)都可以使用允許的最大長(zhǎng)度來(lái)進(jìn)行驗(yàn)證.無(wú)效的數(shù)據(jù)可以被明確地處理,通過(guò)關(guān)閉通道或連接。
4.10.2 拒絕服務(wù)攻擊
AMQP 通過(guò)回復(fù)碼并關(guān)閉通道或連接來(lái)處理錯(cuò)誤.這避免了錯(cuò)誤出現(xiàn)后的模糊狀態(tài).在連接協(xié)商期間,服務(wù)器可假設(shè)特殊條件是因獲取訪問(wèn)服務(wù)器的敵對(duì)嘗試所造成的.對(duì)于連接協(xié)商中的任何異常,一般處理是暫停該連接 (可能是一個(gè)線程)幾秒種時(shí)間,然后再關(guān)閉網(wǎng)絡(luò)連接. 這包括語(yǔ)法錯(cuò)誤,過(guò)大數(shù)據(jù),或認(rèn)證失敗.服務(wù)器應(yīng)該記錄所有這些異常標(biāo)志或阻止客戶端挑起多個(gè)故障.