Xmpp基本知識點

一、Xmpp資源綁定

??????XMPP協議設計中引入了一個抽象的資源綁定過程,何為資源,如何綁定?
??????首先這得從JID的格式設計說起,JID是XMPP前身Jabber協議ID的簡寫,用于唯一標識一個客戶身份。一個合法的 JID 包括一組排列好的元素,包括域名(domain identifier),節點名(node identifier),和資源名(resource identifier),如下:
jid = [ node "@" ] domain [ "/" resource ] ,所有 JID 都是基于上述的結構,類似 { user@host/resource }這種結構。

  • node:是對用戶的抽象,既可以代表一個真實的用戶,也能表示一個虛擬用戶如一個聊天室等。
  • domain:表達了客戶所連接的服務器,在實踐中通常表示一個特定的集群,由同一domain來表示。
  • resource:它通常表示一個特定的會話,連接。對于服務器和和其他客戶端來說,資源名是不透明的。
    ??????資源名的獲得需要經歷一個資源綁定的過程,這個過程按照XMPP協議約定是在SASL握手完成后,由客戶端重新發起初始化流請求后。
    服務器向客戶端聲明資源綁定特性,過程如下:
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'>  
   <stream:features>  
     <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>  
   </stream:features>  

客戶端發起資源綁定請求,并指定一個綁定的資源名

<iq type='set' id='bind_2'>  
     <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>  
       <resource>pc-win-someone</resource>  
     </bind>  
</iq>  

服務端響應資源綁定請求,并返回綁定后的Full JID名

<iq type='result' id='bind_2'>  
     <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>  
       <jid>somenode@example.com/pc-win-someone-server-gen-random-string</jid>  
     </bind>  
</iq>  

??????以上過程即完成了資源綁定,那么資源綁定有什么作用呢,注意查看協議xml中客戶端端請求綁定資源名為pc-win-someone,通常實現中可考慮用客戶端的平臺相關標識,例如 pc-win標示pc下的windows平臺等,標識連接客戶端的平臺和自身名稱,但XMPP協議約定resource由服務端按照每客戶端生成隨機值,用于唯一標識一個客戶端一次連接會話。因此服務端的實現在客戶端請求資源名后添加了隨機生成的唯一后綴,用于區分不同的客戶端連接。

那么如此設計的目的何在?

??????主要考慮方便同賬號用戶的多點登陸(手機、pad、pc端等多點同時在線),通過resource區分同一用戶的不同接入點,由node+domain+resource組成唯一的用戶在線標識。通過用戶ID形成一對多的用戶接入映射,方便獲得同一賬號的多個接入信息,可靈活的設計多點登陸時用戶的自選策略(是否踢下其他登陸、或選擇最近登陸接收消息等)。

二、Xmpp安全機制

??????XMPP(Extensible Messaging and Presence Protocol)是一個應用于實時通信的開放協議,定義了有關即時消息通信的各方面內容,本文主要是關于XMPP安全機制的介紹以及設計實現思考。

??????XMPP包含一個保證流安全的方法來防止篡改和偷聽,包括兩個層次的安全機制,分別是TLS(Tansport Layer Security)和 SASL(Simple Authentication Security Layer)。
TLS主要用于保證傳輸通道安全,SASL用于用戶鑒權認證,協商流程如下:

  1. 客戶端發起,流初始化(建立TCP連接,發送如下格式數據)
<stream:stream  
     from='juliet@im.example.com'  
     to='im.example.com'  
     version='1.0'  
     xml:lang='en'  
     xmlns='jabber:client'  
     xmlns:stream='http://etherx.jabber.org/streams'>  
  1. 服務端應答流初始化
<stream:stream  
     from='im.example.com'  
     id='t7AMCin9zjMNwQKDnplntZPIDEI='  
     to='juliet@im.example.com'  
     version='1.0'  
     xml:lang='en'  
     xmlns='jabber:client'  
     xmlns:stream='http://etherx.jabber.org/streams'>  
  1. 服務端發送TLS流特征說明
<stream:features>  
     <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>  
         <required/>  
     </starttls>  
</stream:features>  
  1. 客戶端發起TLS握手
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>  
  1. 服務端應答
    -- 握手成功,繼續
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>  

-- 握手失敗,結束流,關閉TCP連接

<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>  
</stream:stream>  
  1. 握手成功后,客戶端重新初始化加密流,并采用安全加密傳輸(通常由SSL實現),注意:這一步之后的交互數據全部經過加密傳輸TLS協商完成。
<stream:stream  
     from='juliet@im.example.com'  
     to='im.example.com'  
     version='1.0'  
     xml:lang='en'  
     xmlns='jabber:client'  
     xmlns:stream='http://etherx.jabber.org/streams'>  
  1. 服務端應答加密流初始化
<stream:stream  
     from='im.example.com'  
     id='vgKi/bkYME8OAj4rlXMkpucAqe4='  
     to='juliet@im.example.com'  
     version='1.0'  
     xml:lang='en'  
     xmlns='jabber:client'  
     xmlns:stream='http://etherx.jabber.org/streams'>  
  1. 服務端發送SASL特征說明,mechanism指出了服務端支持的認證機制,有關SASL認證的機制可參考RFC4422[html] [view plain]
<stream:features>  
     <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>  
       <mechanism>EXTERNAL</mechanism>  
       <mechanism>SCRAM-SHA-1-PLUS</mechanism>  
       <mechanism>SCRAM-SHA-1</mechanism>  
       <mechanism>PLAIN</mechanism>  
     </mechanisms>  
</stream:features>  
  1. 客戶端選擇認證機制
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AGp1bGlldAByMG0zMG15cjBtMzA=</auth>  

??????以下認證過程根據選擇的認證機制有所不同,實踐中真正的實現一般就具體采用一種認證,依賴具體的用戶權限系統進行設計。

這里說說其中一種常見Challenge-Response認證機制

??????客戶端在發送<auth>請求認證時,如上xml片段所示,<auth>元素中包含了一段BASE64編碼的字符串,可以是用戶ID(UID)向服務端表明身份id。
??????服務端接收到認證請求后,發回挑戰碼,挑戰碼由服務器每次隨機生成(挑戰碼也經過BASE64編碼)

<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>  
   cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi  
   LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==  
</challenge>  

??????客戶端接收到挑戰碼后,根據用戶輸入的密碼(原文)按注冊用戶時保存密碼采用Hash算法進行同樣的計算,得到與服務后端數據庫存儲的密碼Hash同樣的值,再以此為種子對挑戰碼進行特定算法計算。

具體算法可以用對稱加密、二次加鹽hash等,經過計算后的挑戰碼作為響應發回給服務端,如下:

<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>  
   dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i  
   T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw  
   MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i  
   LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo  
   YXJzZXQ9dXRmLTgK  
</response>  

服務端根據之前提供的UID獲取用戶保存的密碼hash值,對響應碼進行相同的算法計算后與客戶端傳遞的挑戰碼響應進行碰撞認證
-- 成功,返回

<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>  

-- 失敗,返回

<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>  
</stream:stream>  

結束流,并關閉TCP連接

三、Xmpp消息格式

??????交換消息是XMPP的一個基本用途并且隨之而來的是一個用戶生成一個發給另一個實體的消息節。
XMPP定義的消息節語法完整格式如下:

<message  
    from='juliet@example.com/balcony'  
    to='romeo@example.net'  
    type='chat'  
    xml:lang='en'>  
  <subject>I implore you!</subject>  
  <subject xml:lang='cs'>  
    úpěnlivě prosím!  
  </subject>  
  <body>Wherefore art thou, Romeo?</body>  
  <body xml:lang='cs'>  
     Pro?e? jsi ty, Romeo?  
  </body>  
  <thread parent='e0ffe42b28561960c6b12b944a092794b9683a38'>  
    0e3141cd80894871a68e6fe6b1ec56fa  
  </thread>  
</message>  
  • from屬性:
    ??????設置消息發送方自身的Full JID(node@domain/resource)
  • to屬性:
    ??????設置消息接收方的Bare JID(node@domain),通常第一次發送方無法確知接收方的Full JID,通過服務器中轉路由時由服務器根據Base JID映射接收方的Full JID。 但如果這個消息是在回復之前接收到的消息,則to屬性應該包含對方完整的Full JID。
    ??????如此設計的好處在于:當to屬性設定為Full JID時可以幫助服務器省卻了接收者資源定位(接入定位),在一個IM服務集群環境中這種定位通常意味著一次分布式緩存讀取操作。
  • type屬性:XMPP約定了type的枚舉值,包括:
    ??????chat: 表明在一個點對點會話環境中的聊天消息。
    ??????groupchat:表明在一個多人會話環境中的聊天消息。
    ??????headline: 通常一些系統通知、警告、實時數據更新采用此類型,這類消息不期待客戶端回復或響應,具有很高的實時性,不需要離線存儲。
    ??????normal: 默認的消息類型(缺乏type屬性時),通常表達一種要求接收方必須確認的消息,一般用于系統提示強制用戶確認或取消等。
    ??????error: 表示一個錯誤消息,可能由服務端發送給客戶端,也可能是另一個客戶接收端回應給客戶發送端,此類消息也不需要離線存儲。
  • <subject>子元素:
    ??????表明一個消息主題,通常客戶端實現顯示在聊天窗口標題欄處
  • <body>子元素:
    消息內容部分
  • <subject>和<subject>都允許包含多個元素標簽,不同的標簽根據xml:lang表達了不同的語言(XMPP可是一個國際化協議)
  • <thread>子元素:
    ??????用于跟蹤一個會話, 該元素的作用主要在于方便客戶端實現消息展示(例如:消息歷史查詢時按每次會話折疊顯示消息),每次會話產生一個唯一的thread id,xmpp推薦采用uuid算法,具體用法可參考XEP-0201擴展協議和RFC6121。

還有一種情況是離線消息,它與正常消息的格式和處理機制又有所不同,格式如下所示:

<message from='romeo@montague.net/orchard' to='juliet@capulet.com'>  
  <body>  
    O blessed, blessed night! I am afeard.  
    Being in night, all this is but a dream,  
    Too flattering-sweet to be substantial.  
  </body>  
  <delay xmlns='urn:xmpp:delay'  
     from='capulet.com'   
     stamp='2002-09-10T23:08:25Z'>Offline Storage</delay>  
</message>  

??????離線消息中包含了一個<delay>的子元素,<delay>子元素的from記錄了延遲消息的最后來源方,如上例中from為capulet.com指接收離線消息人連接的服務器,離線消息最終由該服務器發出stamp屬性記錄了離線消息的存儲時間,客戶端實現應顯示該時間而非接收到的時間。

四、XMPP多用戶文本聊天協議(MUC:Multi User Chat)

?????&nbspXMPP在其XEP-0045擴展中定義了一個用于多用戶文本會議(群聊)的協議,類似于聊天室、QQ群等。由于它作為一個標準協議在定義模型上力求完備,涵蓋了現實中的絕大部分IM產品模型,而現實中的IM產品基本都只實現了XMPP定義的模型中的一個子集。

XMPP定義的一些基本概念:

  • 房間:房間的JID標識 room@service (例如, jdev@conference.jabber.org), 這里 "room" 是房間的名稱而 "service" 是多用戶聊天服務運行所在的主機名
  • 房客:房客的JID標識<room@service/nick>,nick是房客在房間的昵稱
  • 崗位:表達了用戶和房間的長期關系。XMPP定義的崗位有:所有者(owner)、管理者(admin)、成員(member)、排斥者(outcast)
  • 角色:表達了用戶和房間的臨時聯系,它只存在與一次訪問期間。XMPP定義的角色有:主持人(moderator)、與會者(paticipant)、游客(visitor)
    有關崗位、角色及其權限詳細描述,參考協議規范描述(角色、崗位和權限)

XMPP MUC協議擴展定義了一個廣泛的用例集合,下面提取一些典型的核心場景來簡要分析說明并輔助實現。

  1. MUC服務發現
    主要用于客戶端向服務器咨詢是否支持MUC,協議交互細節詳見:MUC Discovering
  2. 新建房間
    從房間創建的視角來看,本質上有2種類型的房間:
    instant room 臨時房間(類似于臨時會話),適用于那些臨時選取多個用戶進行會話的場景
    reserverd room 永久房間(類似于固定群)
  3. 銷毀房間
    銷毀房間通常僅限于房間的所有者,臨時房間通常是在房間所有用戶都離開后自動銷毀
  4. 加入房間
    加入房間可以有2種方式,申請和邀請
  5. 發言
    在房間內發言方式從使用場景的角度看通常有3種:
  • 向房間內所有人發言,發言者發送一個消息類型為groupchat的消息,由房間服務轉發給所有與會者。
  • 向部分人發言,這個場景發言者實際創建了一個臨時房間,在該臨時房間內進行群發。
  • 向某一個人發送似有消息,這個場景退化為了一對一的單獨聊天。
  1. 退出房間
    主動退出、管理員(主持人)踢出房間

關于XMPP多用戶文本聊天協議的完整用例集合,請參考協議規范。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,296評論 2 376

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,814評論 18 139
  • 關于XMPP最權威的講解:http://www.jabbercn.org/RFC3920(這個才是最權威的,下面文...
    隨風飄蕩的小逗逼閱讀 1,518評論 1 5
  • 要學習基于XMPP協議的IM開發,首先要熟悉XMPP協議本身。 XMPP協議的組成主要的XMPP 協議范本及當今應...
    RichieQ閱讀 1,899評論 0 6
  • XMPP簡介 XMPP協議簡介 XMPP協議(Extensible Messaging and PresenceP...
    不規則先生閱讀 6,341評論 2 31
  • 前面關于即時通訊基礎Socket,大家學習使用XMPP之前可以先看看即時通訊系列之Socket簡介 前言 前段時間...
    音符上的碼字員閱讀 4,266評論 3 16