XMPP(Extensible Messageing and Presence Protocol:可擴展消息與存在協議)RFC3920html
XMPP沒有指定任何特定的網絡結構,但它一般是採用客戶-服務器 架構進行實現,其中客戶端經過TCP方式使用XMPP訪問服務器,服務器之間也採用TCP方式進行通訊。
如下是這一架構的抽象的示意圖 (這裏 "-" 表示使用 XMPP 通信, "=" 表示可以使用任何協議通信)。node
符號的含義以下:
C1, C2, C3 = XMPP 客戶端
S1, S2 = XMPP 服務器
G1 = 一個XMPP和外部(非XMPP)消息網絡之間進行「翻譯」的網關
FN1 = 一個外部消息網絡
FC1 = 外部消息網絡上的一個客戶端bash
jid = [ node "@" ] domain [ "/" resource ] domain = fqdn / address-literal fqdn = (sub-domain 1*("." sub-domain)) sub-domain = (internationalized domain label) address-literal = IPv4address / IPv6address e.g.: username@mwee.cn/diancan
tip:一個 JID 的每一個合法部分(節點名,域名,資源名)的長度不能(MUST NOT)超過 1023 字節。也就是總體長度(包括 '@' 和 '/' )不能超過 3071 字節。服務器
<?xml version='1.0'?> <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> .... </stream:stream> <?xml version='1.0'?> <stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> .... </stream:stream>
一個XML流至關於一個會話期間全部XML節的一個信封。咱們能夠簡單的把它描述成下圖:網絡
通用屬性
如下五種屬性通用於 message, presence, 和 IQ 節:架構
<message/>節類型能夠被看做是一個"push"機制用於一個實體推送信息給另外一個實體,相似發生在email系統中的通訊. 全部消息節應該處理一個代表預約的消息接收者的'to'屬性;接收了這樣一個節以後,一個服務器應該路由或遞送它給預約的接收者.dom
<presence/> 元素能夠被看做一個基本的廣播或「出版-訂閱」機制,用於多個實體接收某個已訂閱的實體的信息(在這裏,是網絡可用性信息). 一般,一個發行實體應該不帶'to'屬性發送一個出席信息,這時這個實體所鏈接的服務器應該廣播或複用那個節給全部訂閱的實體.不管如何,一個發行實體也能夠帶'to'屬性發送一個出席信息節,這時服務器應該路由或遞送這個節給預約的接收者.ui
信息/查詢(Info/Query),或曰IQ,是一個 請求-迴應 機制,某些狀況下相似[HTTP].IQ語義學使一個實體可以向另外一個實體作出請求並作出應答. 請求和應答所包含的數據定義在IQ元素的一個直接的子元素的名字空間聲明中, 而且由請求實體用'id'屬性來跟蹤這一交互行爲. 於是,IQ交互伴隨着一個結構化的數據交換的通用模式例如 get/result 或 set/result (儘管有時候會以一個錯誤信息應答某個請求):spa
"C"表示從客戶端發給服務器,"S"表示從服務器發給客戶端.net
C: <?xml version='1.0'?> <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> S: <?xml version='1.0'?> <stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> ... encryption, authentication, and resource binding ... C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'> <body>Art thou not Romeo, and a Montague?</body> </message> S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'> <body>Neither, fair saint, if either thee dislike.</body> </message> C: </stream:stream> S: </stream:stream>
客戶端-服務器
如下例子展現一個客戶端使用STARTTLS保護數據流
1: 客戶端初始化流給服務器: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'> 2: 服務器發送一個流標籤給客戶端做爲應答: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'> 3: 服務器發送 STARTTLS 範圍給客戶端(包括驗證機制和任何其餘流特性): <stream:features> <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'> <required/> </starttls> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features> 4: 客戶端發送 STARTTLS 命令給服務器: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> 5: 服務器通知客戶端能夠繼續進行: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> (或者): 服務器通知客戶端 TLS 握手失敗並關閉流和TCP鏈接: <failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> </stream:stream> 6: 客戶端和服務器嘗試經過已有的TCP鏈接完成 TLS 握手. 7: 若是 TLS 握手成功, 客戶端初始化一個新的流給服務器: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'> (或者): 若是 TLS 握手不成功, 服務器關閉 TCP 鏈接. 8: 服務器發送一個流頭信息應答客戶端,其中包括任何可用的流特性: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'> <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>PLAIN</mechanism> <mechanism>EXTERNAL</mechanism> </mechanisms> </stream:features> 9: 客戶端繼續 SASL 握手
...