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

XMPP詳解

XMPP(eXtensible Messaging and Presence Protocol,可擴展消息處理和現場協議)是一種在兩個地點間傳遞小型結構化數據的協議。在此基礎上,XMPP協議已經被用來構建大規模即時通訊系統、遊戲平臺、協做空間及語音和視頻會議系統。編程

XMPP由幾個小的構造塊組成,並在此基礎上擴展出了更多的構造塊。XMPP中有衆多系統:發佈-訂閱服務、多人聊天、表單檢索與處理、服務發現、實時數據傳輸、隱私處理及遠程過程調用等。安全

大多數社交媒體(Facebook及Twitter)也採用了XMPP協議。服務器

什麼是XMPP

與其餘協議同樣,XMPP定義了在兩個或者更多通訊實體間傳遞數據所採用的格式。對於XMPP,實體一般是指客戶端服務器,可是其也容許客戶端與客戶端或服務器端與服務器端的通訊。網絡

在XMPP上交換的是XML數據,採用這種格式,使XMPP協議得到了極大的可擴展性,由於使用XML能夠方便的新增功能並保證先後向兼容。使用XML較二進制協議佔用更大的帶寬,但得到的優點是具備了幾乎無限的可擴展性。session

用戶能夠向XMPP Standards Foundation註冊協議擴展。負載均衡

在XMPP中,XML數據被組織爲了一對流,每一個流分別對應通訊的一個方向。每一個XML流均由一個開始元素、後跟XMPP節和其餘頂級元素,而後是一個結束元素組成。每一個XMPP節(可帶有子元素及屬性)均是該流的一級子元素。在XMPP鏈接末尾,這兩個流造成了一對有效的XMPP文檔。編程語言

XMPP節構成了該協議的核心部分,而XMPP應用程序則關注如何發送和響應各類類型的節。節可能包含網絡上其餘實體的信息、相似於電子郵件的我的消息或爲計算機處理而設計的結構化數據。ide

<message to=’elizabeth@longbourn.lit’ from=’darcy@pemberley.lit/dance’ type=’chat’>

         <body>what think you of books</body>

</message>

在一個典型的XMPP會話中,一個上述的節將會從darcy的XMPP客戶端發送到她的XMPP服務器,她的服務器將會注意到該節的目的地是某個遠程服務器上的一個實體,所以與該遠程服務器先創建XMPP鏈接,並將消息轉發該處。工具

這種通訊網絡與電子郵件相似,但與電子郵件服務器不一樣的是,XMPP間的服務器能夠直接通訊,而不須要藉助中間服務器。加密

這種直接通訊避免了垃圾信息的干擾,且還支持經過TLS(Transport Layer Security,傳輸層安全)來加密通訊並經過SASL(Simple Authentication and Security Layers,簡單身份驗證與安全層)實現身份驗證機制。

XMPP使用傳遞短小信息來設計的,而非針對大型數據塊,但XMPP可以用來協商並創建可在端點間傳遞大型數據塊的帶內或者帶外傳輸。

XMPP歷史

最初各大公司發佈的ICQ均基於其公司運營的專有協議和網絡(ICQ,Yahoo Pager)。

開發人員企圖互通這些IM的努力因爲協議的閉源特性失敗了。

1991年1月Jeremie Miller發佈了Jabber項目,Jabber是基於XML的去中心化的即時通訊協議,同時也是一個叫jabberd的服務器實現。

2000年5月,Jabber的核心協議穩定,jabberd也正式發佈了。

2001年,JSF(Jabber Software Foundation,Jabber軟件基金會)成立,並開始圍繞jabber協議作規範性工做。

2002年12月,JSF向IETF提交了核心規範,併成立了一個IETF小組。

2004年10月,這個標準化進程產生了Jabber協議的改進版,更名爲XMPP,其文檔成爲RFC標準,編號分別爲3920、392一、3922和3923。

最初開發人員向JSF提交的擴展稱爲JEP(Jabber Extension Proposal,Jabber擴展提議)。最終隨着Jabber過分到XMPP,JSF改名爲XSF(XMPP Standard Foundation,XMPP標準基金會)和XEP(XMPP Extension Proposal,XMPP擴展提議)。

2005年XMPP技術開始大規模部署,例如Google Talk。

先進有大約300個XEP,並有數十種客戶端和服務端實現,開源及商用均有,實際上,任何編程語言均可以找到這樣一個庫來加速XMPP開發進程。

XMPP網絡

任何XMPP網絡都是由若干角色組成,能夠分爲服務器端、客戶端、組件和服務器插件。

XMPP網絡與WWW網絡及EMAIL網絡不一樣,XMPP服務器之間尋址只會跳一次,而EMAIL協議則會有多箇中轉服務器,XMPP保存完整的列表。

 

服務器

XMPP服務器是任何XMPP網絡的通訊系統,服務器的任務就是爲XMPP節提供路由。不管這些節是從內部的一個用戶發往另一個用戶仍是本地用戶發送給服務器。

一組可以相互通訊的XMPP服務器構成了XMPP網絡。

XMPP服務器老是容許用戶鏈接到本身,可是也能夠編寫直接使用服務器-服務器協議的應用和程序,來減輕路由消耗。

Ejabberd、Openfire和Tigase是三種可以運行在Windows,Mac OS X和Linux的開源服務器。

M-Link和Jabber XCP是商用產品。

客戶端

大多數XMPP實體均是客戶端,經過客戶端-服務器協議鏈接到XMPP服務器。

客戶端必須向某個地方的XMPP服務器進行身份驗證。服務器會將該客戶端發送的全部節路由到合適的目的地。

服務器還負責管理客戶端會話的其餘幾個方面,包括花名冊及裸地址。

組件

不只僅是客戶端可以鏈接到XMPP服務器,大多數服務器還支持外部服務器組件。這些組件經過添加某種新服務來加強服務器的行爲。這些組件在服務器內有各自的身份和地址,但運行在外部並經過組件協議通訊。

組件協議(XEP-0114)可讓開發人員以一種服務器不可知的方式建立服務器擴展,例如多人聊天服務。

組件也須要向XMPP服務器進行身份驗證,但要較客戶端的徹底SASL驗證簡單,例如口令。

每一個組件編程服務器內部一個可單獨尋址的實體,在外界看相似於一個子服務器。除了基本節以外,XMPP服務器不會代替已鏈接組件來管理其餘節的路由。

服務器還容許組件在內部自行路由或管理節,於是更爲靈活。

插件

許多XMPP服務器還支持使用插件進行擴展,但插件深刻到服務器內部,有較高的效率以及最低的通用性。

插件通常是綁定特定類型的服務器的。

XMPP尋址

XMPP網絡上的每一個實體都有一個或多個地址(稱爲JID,jabber identifier)。一般相似於:

darcy@pemberley.lit和elizabeth@longbourn.lit就是兩個JID。

JID由三個部分組成,節點、域和資源,域是必須的,其餘兩個部分是可選的。

域是實體(服務器、組件或插件)可解析的DNS名稱。僅由域組成的JID是有效地址,表示服務器地址。指向域的節將由服務器自身處理,並可能被路由到某個組件或插件。

本地部分一般用來識別域中的一個特定用戶,位於@前。本地部分也能夠用來識別其餘對象,如某個聊天室。

JID的資源部分一般會標識一個特定客戶端的XMPP鏈接。對於XMPP客戶端而言,每一個鏈接均被指派一個資源。如darcy@perberley.lit想要鏈接他的書法和圖書館則能夠經過

darcy@perberley.lit/study和darcy@perberley.lit/library來尋址,這樣避免了用戶在打開多個連接時消息沒法找到正確的處理器。主要注意的是,資源部分是區分大小寫的。

JID劃分爲兩種類型:

  • Ÿ   裸JID

完整JID去除資源部分的地址,客戶端的裸JID有些特殊,這是由於服務器本身將處理髮往客戶端的裸JID節。裸JID能夠視爲尋址用戶的帳戶,而不是客戶端。

  • Ÿ   完整JID

最爲具體的地址

XMPP節

核心XMPP工具集由三個基本節組成,分別爲<presence>、<message>和<iq>

XMPP流由兩份XML文檔組成,通訊的每一個方向均有一個文檔,這些文檔有一個根元素<stream:stream>,<stream:stream>的子元素由可路由的節以及與流相關的頂級子元素構成。

<stream:stream>
         <iq type=’get’>
             <query xmlns=’jabber:iq:roster’ />  //請求本身的花名冊
         </iq>
         <presence/>  //通知服務器她已在線並能夠訪問
         <message to=’darcy@pemberley.lit’ from=’elizabaeth@longbourn.lit/ballroom’ type=’chat’>
             <body>
                   I cannot talk of books in a ball-room; my head is always full of something else.
             </body> //發送消息
         </message>
         <presence type=’unavailable’> // 聲明本身不可訪問並關閉
</stream:stream>

通用屬性

from/to/type/id

from的屬性並不是由客戶端提供,而是服務端進行的標記。

presence節

presence提供網絡實體的可訪問性。用戶發出presence節,代表本身上線,這樣能夠會有更大的機率與別人通訊(人們更願意與在線的人交流),可是咱們也不用擔憂任何人均可以看到本身的在線狀態,除非咱們訂閱了該用戶的狀態,訂閱以後,用戶的狀態信息會自動發送到訂閱者處。

實際上,XMPP的presence節是一個簡單的專用的發佈-訂閱方法。

在IM中,presence體如今花名冊(roster)中,花名冊保存有JID列表以及用戶與這些JID的訂閱關係,一旦上線,用戶發送presence節,剩下的就由服務器處理了(通知本身在線,以及獲取聯繫人的狀態信息)

message節

用於從一個實體向另一個實體發送消息,並能夠傳輸任何類型的結構化信息,不保證傳輸可靠性

message是一個很是基礎的推模型,message一般用於IM,groupchat,警告和通知等。

message的type有以下幾種:

  • normal

    相似於email,發出後不等待迴應

  • chat

    用於兩個實體間的實時通訊

  • groupchat

    多用戶聊天室中使用

  • headline

    用於發送警告或通知

  • error

發送錯誤信息

<message from=madhatter@wonderland.lit/foo to=alice@wonderland.lit type="chat">
  <body>Who are you?</body>
  <subject>Query</subject>
</message>

除了type以外,典型的message節中還包含from、to或者id屬性(用於目的追蹤)。

to中的JID爲消息的接受者,from是發送者的JID,可是from屬性並不是由客戶端提供,而是發送者的服務端提供的,以免地址模仿。

message節中也能夠包含未在XMPP協議中定義的負載,能夠用於擴展。

IQ節

表示Info/Query,爲XMPP通訊提供請求及響應機制,相似於GET/POST/PUT方法。

IQ只能包含一個payload,而且定義了須要由服務器處理的請求或者動做。相對於message來講,IQ具備更好的可靠性,因其要求收到迴應。

IQ中包含有id屬性,用於識別服務器發回的響應。

  • get

    用於請求信息,相似於HTTP Get

  • set

    提供信息或請求,相似於HTTP POST/PUT

  • result

    響應請求,相似於HTTP 200

  • error

    錯誤信息

例子

  • 發送獲取花名冊請求
<iq from=alice@wonderland.lit/pda id="rr82a1z7" to=alice@wonderland.lit type="get">
<query xmlns="jabber:iq:roster"/>
</iq>
  • 服務器返回花名冊
<iq from=alice@wonderland.lit id="rr82a1z7" to=alice@wonderland.lit/pda type="result">
    <query xmlns="jabber:iq:roster">
        <item jid="whiterabbit@wonderland.lit"/>
        <item jid="lory@wonderland.lit"/>
        <item jid="mouse@wonderland.lit"/>
        <item jid="sister@realworld.lit"/>
    </query>
</iq>            
  • 用戶新增一個聯繫人
<iq from=alice@wonderland.lit/pda id="ru761vd7" to=alice@wonderland.lit type="set">
    <query xmlns="jabber:iq:roster">
        <item jid="madhatter@wonderland.lit"/>
    </query>
</iq>
  • 服務器響應
<iq from=alice@wonderland.lit id="ru761vd7" to=alice@wonderland.lit/pda type="result"/>

error節

具備明確的結構,一般包含原節內容,通用錯誤信息以及應用程序特有的錯誤條件和信息(可選)

可擴展

XMPP協議是基於XML的協議,所以其天生提供了很好的可擴展性。咱們能夠用XMPP傳遞各類信息,包括連接、位置信息,Web Service等。

鏈接生命週期

發送XMPP節一般須要創建一個通過身份驗證的XMPP會話,包括鏈接、流的創建、身份驗證以及斷開鏈接。

鏈接

在發送任何節以前,須要創建XMPP流,在XMPP流存在以前,必須創建通往XMPP服務器的鏈接。

當XMPP客戶端或者服務器鏈接到另一個XMPP服務器時,首先要查詢SRV記錄,該記錄保存有特定域的服務器列表。查詢應答中能夠包含多條SRV記錄,這樣就能夠在多個服務器中創建負載均衡鏈接。

若是沒有找到合適的SRV記錄,那麼程序將試圖直接鏈接到指定域。

流的創建

Ÿ   一旦創建經過給定XMPP服務器的鏈接,XMPP流就啓動了

Ÿ   向服務器發送<stream:stream>,就能夠打開XMPP流,服務器發送響應流的起始標記<stream:stream>進行響應

創建XMPP流以後就能夠來回發送各類元素

Ÿ   服務器發送<stream:feature>元素,列舉XMPP流中支持全部功能,大多數與可用的加密和身份驗證選型有關

身份驗證

XMPP容許進行TLS(Transport Layer Security,傳輸層安全)加密,並且大多數客戶端默認使用該功能。

一旦服務器通告TLS支持後,客戶端就會啓動TLS鏈接並將當前套接字升級爲加密套接字而不斷開鏈接。一旦TLS加密確立,就會建立一對新的XMPP流。

XMPP中的身份驗證使用SASL(Simple Authentication and Security Layers,簡單身份驗證與安全層)協議並支持多種身份驗證機制(取決於服務器)。

一旦完成身份驗證,客戶端必須爲鏈接綁定一個資源並啓動一個會話,經過<bind>和<session>元素髮送。

當兩臺服務器相互鏈接時,身份驗證步驟稍稍不一樣。

鏈接斷開

當用戶結束XMPP會話後,他們終止會話並斷開鏈接,最優雅的方式是首先發送無效出席信息,而後關閉<stream:stream>元素。

<presence type=’unavailable’>
</steam:stream>
相關文章
相關標籤/搜索