基於XMPP的即時通訊系統的創建(四)— 協議詳解

Presence

在XMPP協議中,咱們使用presence來獲取用戶是否已經上線以及是否能夠通訊的狀態。html

爲了可以知道本身聯繫人的狀態以及讓聯繫人知道本身的狀態,用戶上線後須要訂閱聯繫人的狀態,聯繫人也一樣須要訂閱用戶的狀態。node

經過下面的消息訂閱聯繫人的狀態:編程

<presence from="alice@wonderland.lit" to="sister@realworld.lit" type="subscribe"/>

當聯繫人接收/拒絕訂閱時,會發送消息的消息體(sucribed/unsubscribe)迴應。緩存

一般客戶端是自動迴應這些消息的,當咱們訂閱了聯繫人的狀態以後,也會受到聯繫人的狀態變動信息。安全

還能夠經過嵌入<show/>(chat/away/xa/dnd)和<status/>元素表示更加豐富的信息。服務器

<presence>
    <show>away</show>
    <status>Having a spot of tea</status>
</presence>

須要注意的是presence節是佔用帶寬最多的節,任何對該節內容的擴展都須要慎重。網絡

另外,presence還提供priority屬性用來標識資源的優先級(-127-128),負數優先級的資源將沒法接收消息,除非顯式指定,這個特性一般是由服務器實現的。session

另外,咱們能夠經過發送directed presence到其餘用戶,來避免訂閱對方信息,很是適合應用於網絡而上的簡短交流。dom

能夠經過發送<presence type=」unavailable」 />發送下線通知,服務器會完成消息保存,聯繫人通知等一系列操做。ide

presence也有其富文本形式,能夠包含更多信息,但不建議在presence中使用(資源和帶寬)。Publish-Subscribe[XEP-0060]和Personal Eventing Protocal[XEP-0163]提供了相似功能,但presence是針對整個花名冊廣播的。

服務器返回的花名冊中還能夠包含更加豐富的信息,包括用戶組以及訂閱狀況。

用戶對花名冊的修改也能夠經過發送IQ-set(rost-push)同步到服務器及其餘客戶端上(用戶可能有手機/pad等)。這種只推送變動的機制能夠簡化客戶端編程並節省流量。

Instant Messaging

消息發送流程

  1. user1向user2發送消息,user1位於domain1,user2位於domain2
  2. user1的client1向server1發送消息節,server1設置from屬性
  3. server1投遞消息給server2(直接通訊)
  4. server2收到消息並檢查user2是否在線並投遞
  5. normal

message消息類型

獨立消息,將會立刻投遞或者緩存,是默認消息類型

  • chat

  用戶聊天,經過session創建,一般處理一系列消息

  • groupchat

  多人聊天,一般此類型會指定一個組件或者模塊處理多人聊天,該模塊會爲每一個參與者發送消息

  • headline

  全體通知,不會緩存,當即投遞

  • error

  錯誤信息節,反饋錯誤信息

延時投遞

若是用戶不在線,則消息被緩存,用戶登陸後,消息推送給用戶,並攜帶消息原始產生時間,用於客戶端對消息進行排序。

能夠參考Delayed Delivery[XEP-0203]

Chat session

chat session用於用戶頻繁交流的狀況,這相似於現實狀況中的聊天,其創建過程爲:雙方用戶在消息交互中知道了對方的Full JID,所以能夠直接通訊,響應的機制稱爲chat session。

狀態通知

相似於QQ的「正在輸入」功能,讓交互雙方瞭解即時狀態。

該功能擴展由XEP-0085定義。若是用戶不但願對方看到本身的狀態,能夠選擇不響應<active/>節。

已經定義好的狀態有:Starting,Active,Composing,Paused,Inactive,Gone

 

消息相似於:

<message from=you@yourdomain.tld/work to=daughter@yourdomain.tld type="chat">
    <body>Hi honey!</body>
    <active xmlns="http://jabber.org/protocol/chatstates"/>
</message>

格式化消息

能夠在message消息中加入XHTML用於富文本展現。

協議能夠在[XEP-0071]中找到。

<message from=you@yourdomain.tld/home to=friend@theirdomain.tld type="chat">
    <body>I love this movie I saw last night, it's awesome!</body>
        <html xmlns="http://jabber.org/protocol/xhtml-im">
            <body xmlns="http://www.w3.org/1999/xhtml">
                <p>
                    I <em>love</em>, this new movie I saw last night, it's     <strong>awesome</strong>!
                </p>
            </body>
        </html>
</message>                

很容易注意到,消息中包含一個不包含格式的文本,以及XHTML格式的文本,是由於考慮到客戶端若是不支持HTML,也能夠正常展現。

HTML節中不能夠包含HEAD中的信息,也不能包含腳本(安全性考慮)。

vCards

也就是虛擬名片,用戶在聊天時能夠經過虛擬名片查看相關信息。

參考[XEP-0054]

虛擬名片服務經過發送IQ請求查看和更新,但須要注意的是,更新虛擬名片時須要發送完整的信息而不是隻有要更新的部分。

查詢請求:

<iq from=mouse@wonderland.lit/pool id="pw91nf84" to=alice@wonderland.lit type="get">
    <vCard xmlns="vcard-temp"/>
</iq>

返回的消息:

<iq from=alice@wonderland.lit id="pw91nf84" to=mouse@wonderland.lit/pool type="result">
    <vCard xmlns="vcard-temp">
        <N>
            <GIVEN>Alice</GIVEN>
        </N>
    <URL>http://wonderland.lit/~alice/</URL>
    <PHOTO>
        <EXTVAL>http://www.cs.cmu.edu/~rgs/alice03a.gif</EXTVAL>
    </PHOTO>
    </vCard>
</iq>

更新名片:

<iq from=alice@wonderland.lit/pda id="w0s1nd97" to=alice@wonderland.lit type="set">
    <vCard xmlns="vcard-temp">
        <N>
            <GIVEN>Alice</GIVEN>
        </N>
        <URL>http://wonderland.lit/~alice/</URL>
        <PHOTO>           
<EXTVAL>http://www.cs.cmu.edu/~rgs/alice03a.gif</EXTVAL> </PHOTO> <EMAIL> <USERID>alice@wonderland.lit</USERID> </EMAIL> </vCard> </iq>

阻塞和過濾通訊

相似於QQ可黑名單機制,能夠對某人隱身,不看某人的消息或屏蔽某個域的消息等等;固然也包括對名單的修改。

該功能可支持的粒度很是細,參考標準[XEP-0016],[XEP-0191]。

更多消息擴展

  • Extended Stanza Addressing[XEP-0033]

  發送一條消息給多個接受者而不經過聊天室

  • Advanced Message Processing[XEP-0079]

  控制消息過時,避免消息被本地存儲以及延時投遞等

  • Message Receipt[XEP-00184]

  客戶端層面確認消息是否已經送達

  • Message Archiving[XEP-0136]

  在服務器上存儲消息,而不是在客戶端機器上存儲

Service Discovery

咱們須要知道系統中有哪些實體,以及該實體支持哪些服務,爲了完成這些操做,引入了實體發現和服務發現的概念。

Items and Info

XMPP 服務發現協議[XEP-0030]定義了兩個基本的發現方法。首先發現disco#items,disco#info。

  • 向服務器發送發現實體請求
<iq from=hatter@wonderland.lit/home id="xl391n47" to="wonderland.lit" type="get">
    <query xmlns="http://jabber.org/protocol/disco#items"/>
</iq>
  • 服務器響應發回實體列表
<iq from="wonderland.lit" id="xl391n47" to=hatter@wonderland.lit/home type="result">
    <query xmlns="http://jabber.org/protocol/disco#items">
        <item jid="conference.wonderland.lit"/>
        <item jid="notify.wonderland.lit"/>
    </query>
</iq>
  • 查詢實體支持的功能
<iq from=hatter@wonderland.lit/home id="gq02kb71" to="conference.wonderland.lit" type="get">
    <query xmlns="http://jabber.org/protocol/disco#info"/>
</iq>
  • 返回實體支持功能結果列表
<iq from="conference.wonderland.lit" id="gq02kb71" to=hatter@wonderland.lit/home type="result">
    <query xmlns="http://jabber.org/protocol/disco#info">
        <identity category="conference" type="text" name="Chatrooms"/>
        <feature var="http://jabber.org/protocol/muc"/>
        <feature var="jabber:iq:register"/>
        <feature var="vcard-temp"/>
    </query>
</iq>

Using Service Discovery with Servers and Services

服務發現一樣適用iq-get的disco#items/disco#info這兩個查詢操做,只是將查詢是服務而非實體。

具體的查詢步驟較爲複雜。

Using Service Discovery with Clients

Explicit Service Discovery

這種場景應用於用戶的花名冊向用戶返回是否在線的信息,這種判斷是否在線的信息帶有Full JID,所以能夠經過disco#info/disco#item來查詢。

可是這種查詢可能返回某個Full JID攜帶的所有信息,致使數據量過大,所以引入了下面的方式。

Entity Capabilites: Service Discovery Shorthand

是對上面方法的改進,經過將實體支持的特性HASH爲一組特徵嗎,客戶端接收該特徵碼後與本地存儲進行比較,若是已有該特徵碼,則能夠得到支持的特性列表;若是客戶端沒有緩衝該特徵碼,則從新發送disco#info消息獲取,並緩存。

採用此種方法能夠節省響應的資源。

而且經過presence節就能夠獲取客戶端支持的功能了。

Data Forms

相似於HTML的表單,有工做流的特徵,能夠實現用戶驗證碼輸入和確認等功能。

由[XEP-0004]定義。

Multi-Party Interaction

MCU 基礎

  1. 多人聊天最初被稱爲groupchat,後來的迭代版本改進爲Multi-User Chat(UMC)[XEP-0045]。
  2. MCU的基本思想是用戶加入到一個聊天室,而聊天室會組播消息,聊天室起到消息反射器的做用
  3. 聊天室有以下特徵

3.1    消息在全部的參與者中共享

3.2    全部的參與者都有一個room roster

3.3    參與者都使用其nickname標識,而不是實際的JabberID

3.4    房間共享參與信息

3.5    參與者不只限於人,也能夠是服務等

  1. 聊天室有其本身的JID,且該JID是服務器的一個組件,所以具備不一樣的域,如服務器的域稱爲:wonderland.lit,組件的域爲conference.wonderland.lit,實現MCU須要相應的組件,服務器根據域的不一樣將消息路由到對應的組件上處理。
  2. 加入聊天流程

5.1    用戶發送presence消息

5.2    聊天室向成員廣播該presence

5.3    聊天室向用戶發送成員的presence

5.4    聊天室向用戶發送一些歷史消息好讓用戶參與討論,消息數目可配置,且消息帶有時間戳

<delay xmlns="urn:xmpp:delay" stamp="2008-11-07T18:42:03Z"/>

5.5    以後的聊天消息再也不攜帶時間戳

5.6    聊天室之間的消息往來,消息類型爲groupchat

  1. 若是用戶向聊天室的成員發送消息,消息類型爲chat,但消息實際上使用用戶發送給聊天室的,聊天室會改寫from/to字段爲實際接受者的JID。
  2. 若是離開聊天室則會發送退席消息

<presence from=dormouse@wonderland.lit/sleepspace to=teaparty@conference.wonderland.lit/Dormouse type="unavailable"/>

成員管理

羣組中有多重角色,不一樣的角色擁有不一樣的權限,能夠將用戶臨時踢出,或加入黑名單等。

具體有:outcast,visitor,participant,member,moderator,admin,owner。

另外房間也有不一樣的類型,有指定名單的,有臨時的,有隱藏的,有固定的等。

暱稱

用戶能夠設置其在聊天室內的暱稱,參考In-Band Registration[XEP-0077]。

配置

多人聊天能夠進行配置,有很是多的可配置項,列出以下。

配置項

做用

allowinvites

是否容許普通成員邀請

changesubject

是否非管理員可以更改聊天室主題

enablelogging

是否開啓記錄歸檔

getmemberlist

是否可以獲取成員列表

lang

語言

maxuser

最大參與者數量

membersonly

是否僅會員可加入(適用於member類型聊天室)

persistentroom

房間是否爲永久(全部成員退出也不會刪除)

presencebroadcast

是否廣播presence消息,對大room有用

publicroom

該room是否可被發現

roomadmin

設置room管理員

roomdesc

設置room描述

roomname

設置room名稱

roomowner

設置room 全部者

whois

控制是否匿名等

數據傳輸

除了文字以外,MCU還能夠傳輸地理信息,文件和進行遠程調用等。

Publish/Subscribe

實際上就是消息系統中的推模式,主要分三個步驟完成:首先訂閱一個主題;其次發佈一個消息;最後消息被推送到訂閱客戶端。[XEP-0060]

Subscriptions

訂閱者須要訂閱一個源,發佈者也將消息發佈到這個源。

流程:

  1. 用戶發送訂閱請求
  2. 服務器響應該訂閱請求

若是成功則能夠接收消息了,若是失敗,則有多是要求更多的配置信息

  1. 訂閱者對訂閱進行配置(可選)
  2. 訂閱者請求配置項
  3. 源返回訂閱配置表單
  4. 用戶解除訂閱
  5. 服務器返回解除訂閱響應

Publishing and Receiving Notifications

主要分爲兩個部分。

發佈方發佈消息到源;服務器將源的消息經過message的形式投遞給訂閱方。

須要注意的是:發佈方只負責將消息推送至源,投遞的邏輯由訂閱方的服務器完成。

Payloads

用戶能夠選擇是否在通知中攜帶payloads,如通知中包含頭像信息時,只須要metadata,無需具體的數據。

是否啓用payload能夠經過配置項deliver_payloads來實現。

Items

是否保存items也是能夠配置的,能夠經過persist_items配置。

保存/不保存數據的node分別稱爲persistent nodes/transient node。

Discovering Nodes

nodes及其服務能夠經過disco#info/disco#item來查詢

返回的結果能夠經過以上兩個命令進一步查詢,直到找到想要訂閱的node。

Personal Eventing

若是用戶想訂閱某個好友的動態,可使用用戶的JID做爲datanode,相應的簡化協議稱爲PEP[XEP-0163](Personal Eventing Protocal)。

用戶能夠應用PEP協議,在本身的Presence消息中包含本身的愛好信息,服務器收到該presence後,將會根據此愛好向用戶推送好友的動態。

包括User Tune,User Location,User Activity,User Mood,User Nickname,User Avatar等。

Design Decision

  1. 儘可能不要修改XMPP的核心協議,而是應該試着經過新的namespace去擴展它
  2. 因爲presence佔用了大約90%的數據流量,須要控制presence節中的數據
  3. 須要儘可能簡化XMPP客戶端的設計,尤爲是須要減小對服務器端的壓力
  4. 儘可能重用已有協議,而不是從新設計一個
相關文章
相關標籤/搜索