轉(zhuǎn)載自網(wǎng)絡(luò),來(lái)源未知
1.1. Introduction 簡(jiǎn)介
第一個(gè)Jabber技術(shù)的應(yīng)用是由開源社區(qū)發(fā)起并一直領(lǐng)導(dǎo)的即時(shí)消息的實(shí)時(shí)系統(tǒng)。Jabber即時(shí)消息(IM)系統(tǒng)和現(xiàn)有IM服務(wù)相比較由以下幾個(gè)關(guān)鍵特點(diǎn):
XML為基礎(chǔ)
分布式網(wǎng)絡(luò)
開放的協(xié)議和內(nèi)核代碼
模塊化的、可擴(kuò)展的系統(tǒng)架構(gòu)
本文檔提供一個(gè)關(guān)于Jabber系統(tǒng)架構(gòu)的高階概述,主要集中介紹Jabber開源服務(wù)器的設(shè)計(jì),目前的版本是1.4(譯注:目前最新版本是2.0)。關(guān)于Jabber的XML協(xié)議的相關(guān)內(nèi)容,請(qǐng)參見Jabber Protocol Overview參考文檔(http://docs.jabber.org/general/html/protocol.html)。
(注:本文檔綜合了以下文件內(nèi)容:Jeremie Miller 1999年11月19日的《Jabber系統(tǒng)架構(gòu)概況》,Peter Millard 在2000年4月25日關(guān)于此文檔的上一個(gè)版本,Peter Saint-Andre 2000年11月6日的《Jabber白皮書》
1.2. Foundations 基礎(chǔ)知識(shí)
Jabber在設(shè)計(jì)上很大程度上沿襲了Internet上最成功的消息系統(tǒng):即email。這樣Jabber就可以在一個(gè)使用共同協(xié)議的服務(wù)器組成的分布式網(wǎng)絡(luò)上提供通信,連接這個(gè)網(wǎng)絡(luò)的客戶端,可以象接收消息一樣發(fā)送消息給同一個(gè)服務(wù)器或其他Internet上的服務(wù)器上的用戶。不過(guò),盡管email是一個(gè)存儲(chǔ)-轉(zhuǎn)發(fā)系統(tǒng),但Jabber轉(zhuǎn)發(fā)消息卻是實(shí)時(shí)的,因?yàn)?/span>Jabber服務(wù)器(連同其他所有Jabber服務(wù)器在內(nèi))知道一個(gè)用戶什么時(shí)候在線。這個(gè)能力被成為在線,也是即時(shí)消息的核心所在。Jabber通過(guò)兩個(gè)附加功能提供這些IM標(biāo)準(zhǔn)特性,這也使得Jabber與眾不同。首先是一個(gè)允許消息系統(tǒng)間協(xié)同作業(yè)的開放協(xié)議。其次是建立在XML上的強(qiáng)大根本,它使得非但是兩個(gè)人之間的通信,甚至是應(yīng)用軟件之間的通信成為了可能。
上述每一個(gè)功能都將在下文進(jìn)行進(jìn)一步的闡述,并進(jìn)一步擴(kuò)展本文檔的內(nèi)容。
1.2.1. Client/Server 客戶端/服務(wù)端
Jabber使用的是客戶端-服務(wù)端的系統(tǒng)架構(gòu),而不是其它一些即時(shí)消息系統(tǒng)使用的客戶端-客戶端的系統(tǒng)架構(gòu)。所有從一個(gè)客戶端發(fā)給另一個(gè)客戶端的Jabber消息和數(shù)據(jù)都必須通過(guò)服務(wù)端。任何一個(gè)客戶端都可以通過(guò)商議與另一個(gè)客戶端自由地建立一個(gè)直接地連接,但這些連接只用于特殊服務(wù)地應(yīng)用。有一些實(shí)例被鼓勵(lì)建立這種連接,比如文件傳輸,但這些實(shí)例必須先通過(guò)一個(gè)客戶端-服務(wù)端形勢(shì)進(jìn)行協(xié)商,才能建立。
1.2.2. Distributed Network 分布式網(wǎng)絡(luò)
Jabber地網(wǎng)絡(luò)體系是模仿e-mail系統(tǒng)地。每一個(gè)用戶都有自己的本地服務(wù)器,并從該服務(wù)器上接收信息,消息和在線信息在這些服務(wù)器之間傳輸。可以添加任意數(shù)目的Jabber服務(wù)器,這些服務(wù)器接受客戶端的連接,并與其它Jabber服務(wù)器進(jìn)行通信。每一個(gè)Jabber服務(wù)器都獨(dú)立于其他Jabber服務(wù)器,并且擁有其自身的用戶列表。通過(guò)Internet,任一Jabber服務(wù)器都可以與其他Jabber服務(wù)器進(jìn)行通話。每一個(gè)用戶都與一個(gè)特殊服務(wù)器(提供注冊(cè)服務(wù)的服務(wù)提供商或行政管理企業(yè))相對(duì)應(yīng),Jabber地址和email地址的形勢(shì)是一樣的,如:stpeter@jabber.org(下面的Jabber ID部分將介紹更多關(guān)于Jabber地址的信息)。
1.2.3. Modular Server 模塊化的服務(wù)器端
Jabber服務(wù)器遵循兩個(gè)主要法則:
1)監(jiān)聽客戶端連接,并直接與客戶端應(yīng)用程序通信
2)與其他Jabber服務(wù)器通信
Jabber開源服務(wù)器被設(shè)計(jì)成模塊化,由各個(gè)不同的代碼包構(gòu)成,這些代碼包分別處理類似用戶認(rèn)證、數(shù)據(jù)存儲(chǔ)(離線消息,花名冊(cè),用戶信息等)等等。另外,服務(wù)器可以通過(guò)附加服務(wù)來(lái)進(jìn)行擴(kuò)展,如完整的安全策略,允許服務(wù)器組件的連接或客戶端選擇,通向其他消息系統(tǒng)的網(wǎng)關(guān)。
一個(gè)模塊化的例子就是通過(guò)Jabber XML翻譯成其他協(xié)議的獨(dú)立“transport”(傳輸器),可以實(shí)現(xiàn)Jabber消息系統(tǒng)與非Jabber消息系統(tǒng)之間進(jìn)行消息和在線信息的交流。這些傳輸器并不是服務(wù)器內(nèi)核。相反,它們是很容易添加到服務(wù)器內(nèi)核服務(wù)器端程序,為終端用戶提供更強(qiáng)大的功能服務(wù)。
1.2.4. Simple Client 簡(jiǎn)單的客戶端
Jabber系統(tǒng)的一個(gè)設(shè)計(jì)標(biāo)準(zhǔn)是必須支持簡(jiǎn)單的客戶端(如同和telnet連接一樣簡(jiǎn)單的客戶端)。事實(shí)上,Jabber系統(tǒng)架構(gòu)對(duì)客戶端只有很少的幾個(gè)限制。一個(gè)Jabber客戶端必須支持的功能有:
通過(guò)TCP 套接字與Jabber服務(wù)器進(jìn)行通信
解析組織好的XML信息包
理解消息數(shù)據(jù)類型
Jabber將復(fù)雜性從客戶端轉(zhuǎn)移到服務(wù)器端。這使得客戶端編寫變得非常容易(一個(gè)證據(jù)就是今天出現(xiàn)了種類繁多的客戶端),更新系統(tǒng)功能也同樣變得容易(這樣,就不用強(qiáng)迫用戶去下載新的客戶端)。Jabber客戶端與服務(wù)端通過(guò)XML在TCP 套接字的5222以上端口進(jìn)行通信,而不需要客戶端之間直接進(jìn)行通信。在實(shí)際應(yīng)用中,許多低階的客戶端功能(如解析XML,理解基本的jabber XML語(yǔ)言類似<message/>,<presence/>,<iq/>)已經(jīng)包含在Jabber客戶端類庫(kù)中,這樣可以讓客戶端的開發(fā)人員更多的注重用戶界面的開發(fā)。
1.2.5. XML Data Format XML數(shù)據(jù)格式
XML是Jabber系統(tǒng)架構(gòu)的核心部分,它最重要的作用是系統(tǒng)的底層可擴(kuò)展性,并能表述幾乎任何一種結(jié)構(gòu)化數(shù)據(jù)。(特別地,Jabber利用XML數(shù)據(jù)流進(jìn)行客戶端-服務(wù)器端以及服務(wù)器端-服務(wù)器端的通信。XML數(shù)據(jù)流一般是由客戶端發(fā)起至服務(wù)端,XML數(shù)據(jù)流的有效時(shí)間直接與用戶的在線會(huì)話有效時(shí)間相關(guān)聯(lián)。)
Jabber嚴(yán)格遵守XML的同時(shí),不需要知道任何關(guān)于信息轉(zhuǎn)發(fā)中介的信息:對(duì)于信息轉(zhuǎn)發(fā)中介沒有任何固有的規(guī)定,也不需要任何關(guān)于信息轉(zhuǎn)發(fā)中介的系統(tǒng)架構(gòu)的知識(shí)。這都是可能的,在另一方面,這也使得提供與第三方服務(wù)(如:IRC,ICQ,AIM)進(jìn)行信息傳輸?shù)膫鬏斊鞯膶?shí)現(xiàn)成為可能。而在Jabber系統(tǒng)內(nèi)部,就像Jabber系統(tǒng)中其它每一個(gè)組件一樣,傳輸器使用XML語(yǔ)音。更多關(guān)于Jabber XML協(xié)議的信息可以在《Jabber協(xié)議概述》(http://docs.jabber.org/general/html/protocol.html)中。
1.3. High-Level Server Architecture 高階服務(wù)器系統(tǒng)架構(gòu)
Jabber服務(wù)器由若干個(gè)組件構(gòu)成,這些組件分別完成Jabber系統(tǒng)中邏輯上獨(dú)立的各個(gè)功能。服務(wù)器的內(nèi)核是一個(gè)轉(zhuǎn)發(fā)組件,這個(gè)組件的唯一功能就是從一個(gè)基本組件往另一個(gè)基本組件進(jìn)行XML解析傳遞。共有四個(gè)這樣的基本組件:接收、連接、執(zhí)行、裝入。這些基本組件解析傳入的XML,轉(zhuǎn)發(fā)給其他基本組件,并使得基本組件的下游組件能夠連續(xù)的使用XML。下面是一個(gè)高階的系統(tǒng)架構(gòu)的演示圖:
一個(gè)服務(wù)器啟動(dòng)后,Jabber服務(wù)器負(fù)責(zé)注冊(cè)的組件通過(guò)Jabber的主程序后臺(tái)(如同在服務(wù)器的配置文件中定義的一樣)執(zhí)行其功能單元(?),并運(yùn)行由這些功能單元組成的信息包(以此來(lái)定義所有信息包的傳送邏輯)。Jabber服務(wù)器的內(nèi)核包括處理以下公共任務(wù)的組件:
會(huì)話管理
客戶端-服務(wù)端的通信
服務(wù)器-服務(wù)器的通信
DNS解決方案
用戶認(rèn)證
用戶注冊(cè)
數(shù)據(jù)庫(kù)查詢
為離線用戶存儲(chǔ)信息
存儲(chǔ)并找回vCards
根據(jù)用戶設(shè)定過(guò)濾信息
群組聊天(多對(duì)多的通信)
系統(tǒng)日志
另外,服務(wù)器內(nèi)核能夠補(bǔ)充“傳輸器”,這些“傳輸器”被設(shè)計(jì)來(lái)解決不同于Jabber開放的XML格式的其他協(xié)議。(詳情見傳輸器部分)。這些傳輸器可以很自然地作為整體服務(wù)器系統(tǒng)架構(gòu)的內(nèi)置組件存在。目前存在進(jìn)行翻譯功能的傳輸器主要是針對(duì)以下的協(xié)議:
AOL Instant Messenger(AIM)
ICQ
Internet Relay Chat(IRC)
MSN Messenger
Rich Site Summary(RSS 0.9)
Yahoo! Messenger
(注:附加的傳輸器可以根據(jù)需要增加到Jabber上,例如為了解決IM不統(tǒng)一的格式,但未來(lái)的傳輸器沒有在本文檔中闡述。)
1.4. Basic Message Flow 基本消息流程
對(duì)于學(xué)習(xí)Jabber系統(tǒng)而言,研究通過(guò)服務(wù)器的典型數(shù)據(jù)流程是一個(gè)好的入門方式。(當(dāng)XML的“消息”元素僅指Jabber開放的XML協(xié)議中規(guī)定的三種主要元素中的一種時(shí),它更能體現(xiàn)Jabber最核心的意圖:通過(guò)使用XML進(jìn)行消息的點(diǎn)對(duì)點(diǎn)發(fā)送。)
下面是關(guān)于該數(shù)據(jù)流程的圖表:
Jabber服務(wù)器(在上述圖表中簡(jiǎn)化為“jabberd”,原義為“Jabber daemon [Jabber后臺(tái)程序]”)在主機(jī)上的用戶會(huì)話的上下文中接收型為“消息”的包體,正常情況下,該包體在5222端口(如果SSL允許并運(yùn)行的情況下也可以是5223端口)通過(guò)一個(gè)直接的TCP套接字產(chǎn)生。如果會(huì)話不存在,jabberd將發(fā)起認(rèn)證流程,該流程將會(huì)在下面的認(rèn)真部分中進(jìn)行介紹。如果會(huì)話存在,消息包將被送往Jabber會(huì)話管理組件(簡(jiǎn)稱“JSM”)。
下面是一個(gè)XML的例子:
<message

to=’psaintandre@aim.jabber.org’

type=’chat’>

<body>Hey, the AIM transport is working great!</body>

</message>
接著,JSM根據(jù)Jabber服務(wù)器的內(nèi)部配置文件上的服務(wù)器名單查找目標(biāo)服務(wù)器的主機(jī)名。通常主機(jī)名都會(huì)被定義;比如,aim.jabber.org在Jabber.com服務(wù)器上的配置文件被定義為指向該主機(jī)的AIM傳輸器(該傳輸器可能在一臺(tái)單獨(dú)的機(jī)器上)。如果主機(jī)名沒有在配置文件中被定義,“dnsrv”組件將把這個(gè)主機(jī)名于一個(gè)IP地址和端口進(jìn)行對(duì)應(yīng)。另外,由于該主機(jī)有問(wèn)題,消息包將會(huì)送到服務(wù)器到服務(wù)器(s2s)組件,在這個(gè)例子中,jabber.org。服務(wù)器到服務(wù)器組件將直接從指定的外部Jabber服務(wù)器(比如jabber.org)或該主機(jī)上一個(gè)傳輸器傳入。在上面的例子中,消息包有意傳遞到aim.jabber.org上的一個(gè)地址,因此,這個(gè)包將被送到jabber.org上的AIM傳輸器,再傳送到一個(gè)AOL Instant Messenger 帳號(hào)(見下面的傳輸器部分)。另一個(gè)方面,最終的結(jié)果是一個(gè)消息從一個(gè)Jabber客戶端流通過(guò)一個(gè)Jabber服務(wù)器流動(dòng)到另一個(gè)Jabber服務(wù)器或外部IM系統(tǒng)。
1.5. Authentication 認(rèn)證
在基本消息流程中提到,消息和在線信息是通過(guò)Jabber服務(wù)器上一個(gè)運(yùn)行中的主機(jī)上的一個(gè)用戶會(huì)話的上下文發(fā)送給Jabber的。在Jabber協(xié)議中規(guī)定,這個(gè)會(huì)話由兩個(gè)XML流保持,一個(gè)是從客戶端到服務(wù)器端,另一個(gè)是從服務(wù)器端到客戶端。下面是一個(gè)會(huì)話的XML顯示:
SEND:<stream:stream

SEND:to=’jabber.org’

SEND:xmlns=’jabber:client’

SEND:xmlns:stream=’http://etherx.jabber.org/streams’>

RECV:<stream:stream

RECV:xmls:stream=’http://etherx.jabber.org/streams’

RECV:id=’39ABA7D2’

RECV:xmlns=’jabber:client’

RECV:from=’jabber.org’>

SEND:<iq id=’1’ type=’set’>

SEND:<query xmlns=’jabber:iq:auth’>

SEND:<username>stpeter</username>

SEND:<resource>Gabber</resource>

SEND:<digest>file881517e9917bb815fed112d811d32b4e4b3aed</digest>

SEND:</query>

SEND:</iq>

RECV:<iq id=’6’ type=’result’/>

(XML for user session goes here)

SEND:</stream:stream>

RECV:</stream:stream>
為了讓服務(wù)器建立一個(gè)會(huì)話,首先必須對(duì)用戶進(jìn)行認(rèn)證。下面的圖表展示的就是認(rèn)證的活動(dòng)流程:
當(dāng)客戶端連接到主機(jī),并發(fā)起一個(gè)XML流時(shí),認(rèn)證流程就開始了。Jabber服務(wù)器會(huì)立即在’jabber:iq:auth’的名字空間中對(duì)’iq’(info/query的簡(jiǎn)稱)類型和’query’子類型的包體進(jìn)行查詢,該名字空間含有對(duì)用戶的認(rèn)證信息。認(rèn)證信息必須包含一個(gè)用戶名和明文密碼(很明顯,這是讓人沮喪的),一個(gè)使用SHA1算法(這個(gè)默認(rèn)的認(rèn)證是設(shè)計(jì)為a.k.a的“數(shù)字認(rèn)證”)加密的密碼,或者是一些符合零度認(rèn)證的數(shù)據(jù)。
一旦認(rèn)證信息被接收到,XML解釋器發(fā)送控制命令給Jabber服務(wù)器的“傳送”組件,該組件將把從客戶端未等待認(rèn)證結(jié)果就發(fā)送過(guò)來(lái)的XML進(jìn)行緩存。主機(jī)(通常,但不全是以JSM形式存在)將把認(rèn)證包傳送到Jabber服務(wù)器的’xdb’組件。xdb組件(’xdb’即“Xml Data Base”――XML基數(shù)據(jù))將把認(rèn)證包發(fā)送給任一注冊(cè)了該認(rèn)證包類型的子組件:例如,明文認(rèn)證包可能通過(guò)檢查文件系統(tǒng)中的XML文件用于’xbd_file’子組件,而數(shù)字認(rèn)證包通過(guò)檢查LDAP用于’xdb_ldap’子組件。傳送組件不作任何處理將認(rèn)證包傳送給xdb組件,xdb組件將把該認(rèn)證包發(fā)送給合適的子組件。另外,為了提高性能,xdb_ldap組件擁有其獨(dú)立的線程池,其運(yùn)作方式與會(huì)話管理器中的線程模式類似。
Xdb組件將認(rèn)證查詢的結(jié)果返回給主機(jī)(同樣,通常是JSM)。如果認(rèn)證失敗,服務(wù)器將返回錯(cuò)誤代碼401給客戶端而不發(fā)起一個(gè)會(huì)話。如果認(rèn)證成功,JSM將開啟一個(gè)會(huì)話(如果需要的話將釋放XML緩存),所有在線信息,消息,以及iq基本信息在用戶會(huì)話的上下文中進(jìn)行來(lái)回傳遞,直到客戶端或服務(wù)端通過(guò)發(fā)送一個(gè)關(guān)閉數(shù)據(jù)流的標(biāo)志(</stream>)終止。
1.6. Jabber Session Manager Jabber會(huì)話管理器
下面是Jabber會(huì)話管理器的活動(dòng)流程:
前面提到,Jabber會(huì)話管理器組件(簡(jiǎn)稱JSM)處理各種類型的包:消息類型、在線信息類型、查詢連接到一個(gè)Jabber主機(jī)上的發(fā)起者或送達(dá)者的Jabber用戶信息。同時(shí),JSM也處理針對(duì)離線用戶的數(shù)據(jù)包。比如,盡管我不在線,你還是通過(guò)我的Jabber ID(stpeter@jabber.org)發(fā)了一條消息給我。JSM將對(duì)這條消息進(jìn)行適當(dāng)處理,很可能一直保存到我再次上線。
JSM通過(guò)從XML流中查找“資源”元素(所謂的“資源”是指設(shè)備、客戶端、我的連接所在的位置;可能是“laptop”、“Gabber”、“home”)來(lái)判斷用戶是否在線。通常,如果一個(gè)數(shù)據(jù)包不包含資源元素,表明該用戶不在線。但有時(shí)資源元素會(huì)因?yàn)殄e(cuò)誤而丟失,因此JSM在肯定用戶真的離線后,才發(fā)送消息包給“離線”組件,“離線”組件可能(舉例而言)會(huì)保存該消息或重新找回一個(gè)vCard。
如果用戶在線,消息、在線信息、iq包不再發(fā)送到離線組件,而是由JSM進(jìn)行處理。實(shí)際上,任何一個(gè)包只會(huì)有一到兩個(gè)可能的狀態(tài):要么它被轉(zhuǎn)發(fā)給用戶,要么它由用戶發(fā)出。因此,JSM開啟兩個(gè)監(jiān)聽,一個(gè)是“to”,一個(gè)是“from”,并將它們路由到Jabber服務(wù)器中指定的模塊中。一旦指定模塊處理完包體,包體將被送回監(jiān)聽程序,以備以后更多模塊進(jìn)行處理,如果所有處理完畢,包體將發(fā)送給消息源或消息目的地。
下面這個(gè)例子將有助于理解。我收到從foobar@jabber.org發(fā)出的一個(gè)消息。我在線,因此消息備送達(dá)JSM。“to監(jiān)聽”監(jiān)聽到有一個(gè)包發(fā)給我,于是發(fā)出一個(gè)請(qǐng)求到已經(jīng)注冊(cè)到JSM的模塊。第一個(gè)響應(yīng)模塊是mod_filter,該模塊按用戶指定的標(biāo)準(zhǔn)對(duì)進(jìn)來(lái)的消息進(jìn)行排序。在這個(gè)例子中(我好像從來(lái)沒有從我們的朋友foobar那里很重要的批評(píng)信息),我配置mod_filter將所有從foobar@jabber.org發(fā)送到我的郵箱的消息通過(guò)SMTP傳輸器轉(zhuǎn)寄。我們說(shuō)mod_filter對(duì)消息進(jìn)行了重新格式化,使得指定接收端現(xiàn)在由smtp.jabber.org取代原來(lái)的jabber.org,然后將包體發(fā)回給“to監(jiān)聽者”。另一個(gè)對(duì)已注冊(cè)組件的呼叫上來(lái),單沒有任何回應(yīng),因此包體被送到stpeter@smtp.jabber.org,使得包體直接轉(zhuǎn)寄到我的電子郵箱中。
需要著重指出的是這個(gè)過(guò)程是重復(fù)的,所以許多模塊都可以在包體完成發(fā)送到或來(lái)自用戶動(dòng)作之前對(duì)包體進(jìn)行處理。這使得JSM擁有了極大的彈性和擴(kuò)展性,因?yàn)檫@樣可以在不對(duì)JSM原有模塊進(jìn)行任何改動(dòng)的基礎(chǔ)上,很容易地添加新地模塊(只需要對(duì)服務(wù)器地配置文件進(jìn)行相應(yīng)修改即可)。
1.7. Threading 線程
Jabber會(huì)話管理器通過(guò)線程來(lái)提高性能。當(dāng)服務(wù)啟動(dòng)時(shí),一定數(shù)量地線程被指派到線程池(實(shí)際數(shù)目由配置文件決定)。當(dāng)系統(tǒng)其他部分的裝載組件反饋消息包給會(huì)話管理器時(shí),會(huì)話管理器動(dòng)態(tài)地從線程池中取出沒有使用的線程,將它們指派給消息端口,這些消息端口正排隊(duì)等候包體(一個(gè)“消息端口”表示支持一個(gè)客戶連接的數(shù)據(jù)結(jié)構(gòu))。如果線程池中沒有可用的線程,會(huì)話管理器可能(但不是必須)創(chuàng)建一個(gè)新的線程,并將它指派給指定的消息端口。下面是這個(gè)過(guò)程的可視化描述:
1.8. Delivery Logic 傳送邏輯
傳送組件是服務(wù)器的核心,因?yàn)樗鼘?shù)據(jù)從一個(gè)基本組件移動(dòng)動(dòng)另一個(gè)基本組件。這個(gè)級(jí)別的數(shù)據(jù)處理邏輯如下圖:
一旦一個(gè)包體被傳送到一個(gè)基本組件(接收、連接、執(zhí)行、裝入),它將被發(fā)送到一個(gè)子組件,類似jpolld或xdb_ldap進(jìn)行進(jìn)一步處理。
一個(gè)預(yù)處理的例子可能是一個(gè)xdb(比如一個(gè)數(shù)據(jù)庫(kù)連接)需要被處理。一個(gè)處理?xiàng)l件可以是JSM中所有有用的路由名字空間的總和。一個(gè)傳送包體改變的例子可以是消息格式的改變,比如加上傳入地址。
1.9. Transports 傳輸器
雖然一個(gè)健壯的、XML基礎(chǔ)的消息系統(tǒng)結(jié)構(gòu)是Jabber項(xiàng)目的核心目標(biāo),另一個(gè)重要的目標(biāo)是進(jìn)行消息系統(tǒng)間的協(xié)同作業(yè)。幸運(yùn)的是,Jabber項(xiàng)目通過(guò)使它的協(xié)議完全開放來(lái)實(shí)現(xiàn)協(xié)同作業(yè)。同時(shí),Jabber項(xiàng)目通過(guò)使用Jabber世界里叫做“傳輸器”的東東來(lái)實(shí)現(xiàn)Jabber開放的XML格式與眾多非Jabber格式間的通信。
當(dāng)一個(gè)Jabber用戶發(fā)送消息給一個(gè)外部(非Jabber)系統(tǒng)的用戶時(shí),消息的傳送包括了一個(gè)傳輸器組件的工作。用戶的Jabber客戶端發(fā)送一個(gè)消息給Jabber服務(wù)器,并指明一個(gè)包含外部系統(tǒng)名的Jabber ID(如psaintandre@aim.jabber.org),而不是發(fā)送給外部IM系統(tǒng)上的一個(gè)用戶。接著Jabber服務(wù)器將數(shù)據(jù)指向指定的傳輸器應(yīng)用程序。如果傳輸器是本地的(在同一臺(tái)機(jī)器上運(yùn)行),Jabber服務(wù)器直接與它進(jìn)行通信。如果傳輸器不在本地運(yùn)行(在另一臺(tái)機(jī)器上),本地服務(wù)器發(fā)送一個(gè)包給遠(yuǎn)程服務(wù)器,該遠(yuǎn)程服務(wù)器將會(huì)把包發(fā)送給指定的傳輸器。一旦傳輸器接收到XML包體,它把信息(或指示)“轉(zhuǎn)變”成另一個(gè)IM網(wǎng)絡(luò)可以識(shí)別的本地包,并把這個(gè)本地包傳送到那個(gè)IM網(wǎng)絡(luò)中。
下面是Jabber傳輸器工作的高級(jí)概覽:
實(shí)際上,一個(gè)傳輸器實(shí)現(xiàn)了一個(gè)代理模式。大多數(shù)傳輸器擁有自己的小型會(huì)話管理器,這個(gè)會(huì)話管理器將在線信息、消息、(有時(shí))查詢信息進(jìn)行Jabber XML協(xié)議和“外部的”(非Jabber)協(xié)議之間的轉(zhuǎn)換。總的來(lái)說(shuō),當(dāng)一個(gè)用戶登陸到Jabber上,傳輸器就為和這個(gè)用戶進(jìn)行通信創(chuàng)建一個(gè)線程。
有時(shí),進(jìn)行Jabber協(xié)議的轉(zhuǎn)換是很直接的,例如,當(dāng)一個(gè)外部協(xié)議是很好的文檔化的(比如IRC協(xié)議,即AIM協(xié)議的“奧斯卡”版本)。而另外有些時(shí)候,對(duì)于封閉的或文檔的自然協(xié)議(如Yahoo! Messenger協(xié)議)進(jìn)行協(xié)議轉(zhuǎn)換就非常困難。人們希望IM統(tǒng)一化組織((http://www.imunified.org (http://www.imunified.org/)))能夠成功開放一些現(xiàn)在還是封閉的消息協(xié)議,或者至少為這些封閉協(xié)議的協(xié)議轉(zhuǎn)換創(chuàng)立一套開放的協(xié)議。
絕大多數(shù)傳輸器都是為了與非Jabber服務(wù)進(jìn)行通信,但也有個(gè)別例外。比如,群組聊天傳輸器,這個(gè)傳輸器使得Jabber用戶們可以在一個(gè)聊天室里進(jìn)行聊天,或者以類似IRC界面的方式進(jìn)行通信。群組傳輸器保留每一個(gè)房間當(dāng)前所有用戶的記錄,并發(fā)送每條消息給該房間的所有用戶,使得一個(gè)房間表現(xiàn)得象一個(gè)映射服務(wù)器。它根據(jù)需要?jiǎng)?chuàng)建和銷毀房間,如果我象加入一個(gè)不存在得房間,傳輸器將創(chuàng)建該房間,如果我使最后一個(gè)離開房間的用戶,傳輸器將在我離開后銷毀這個(gè)房間。每一個(gè)單一的房間通過(guò)類似groupname@groupchatserver這樣的名字進(jìn)行識(shí)別,每一個(gè)參與者通過(guò)一個(gè)對(duì)其昵稱的唯一描述進(jìn)行識(shí)別。比如,在莎士比亞的《麥克白》中女巫們的“groupchat”可能發(fā)生在一個(gè)地址為cauldron@conference.withces.org的房間,女巫們通過(guò)類似cauldron@conference.withces.org/firstwitch的名字進(jìn)行識(shí)別。下面使一個(gè)用戶可能看到的:
1.10. Subscriptions 訂閱
一個(gè)Jabber實(shí)體可以訂閱其他Jabber實(shí)體(如:任何和一個(gè)Jabber ID關(guān)聯(lián)的事物)的在線信息,一個(gè)訂閱本質(zhì)上是被訂閱者同意發(fā)送在線狀態(tài)改變給訂閱者。這個(gè)信息同時(shí)存儲(chǔ)在訂閱者和被訂閱者的名單中。當(dāng)我通過(guò)認(rèn)證并在服務(wù)器上創(chuàng)建一個(gè)會(huì)話,我的在線信息被存放到Jabber會(huì)話管理器中。當(dāng)我改變我的在線狀態(tài)時(shí),<presence/>包將被服務(wù)器處理,服務(wù)器在我的名單中進(jìn)行查詢,并將在線信息狀態(tài)包發(fā)送給所有訂閱我的在線狀態(tài)的Jabber實(shí)體。訂閱包括一下幾種類別,這些類別存放在包含實(shí)體的名單上:
to――另一個(gè)發(fā)送在線狀態(tài)信息給你的實(shí)體
from――另一個(gè)從你這里獲得在線狀態(tài)信息的實(shí)體
both――另一個(gè)發(fā)送再現(xiàn)信息狀態(tài)給你,又從你這里獲取在線信息狀態(tài)的實(shí)體
none――即不從你這里獲取再現(xiàn)信息狀態(tài),又不發(fā)送在線信息狀態(tài)給你的實(shí)體
發(fā)送在線狀態(tài)信息的實(shí)體并不一定是另一個(gè)Jabber用戶,它也可以是一個(gè)外部的服務(wù),比如一個(gè)數(shù)據(jù)流或一個(gè)非Jabber的IM系統(tǒng)。在后面的例子中,非Jabber系統(tǒng)的用戶訂閱通過(guò)一個(gè)傳輸器解決,Jabber用戶注冊(cè)到指定傳輸器(如:icq.jabber.org),以便將在線狀態(tài)信息傳送給非Jabber系統(tǒng)的用戶。一旦Jabber用戶成功注冊(cè),傳輸器就需要知道該用戶什么時(shí)候上線,因此,它發(fā)送一個(gè)在線狀態(tài)信息訂閱請(qǐng)求給該用戶。一個(gè)特殊的帶有“from”特性的在線狀態(tài)信息訂閱數(shù)據(jù)包從傳輸器產(chǎn)生并發(fā)送,其中的數(shù)據(jù)必須可以登錄到本地協(xié)議。
Jabber服務(wù)器包含一個(gè)所有用戶的訂閱信息組成的名單(該名單通常直接存放與文件系統(tǒng)中,盡管這些信息一個(gè)可以存放在數(shù)據(jù)庫(kù)中)。這個(gè)名單被命名為花名冊(cè),很像其他IM系統(tǒng)中的“好友列表”。Jabber的花名冊(cè)存放在服務(wù)器上,這樣用戶就可以自由的從一個(gè)地方到另一個(gè)地方,從一臺(tái)計(jì)算機(jī)到另一臺(tái)計(jì)算機(jī)自由的調(diào)用它。Jabber服務(wù)器根據(jù)用戶意愿對(duì)花名冊(cè)上的對(duì)應(yīng)訂閱關(guān)系進(jìn)行允許、拒絕等操作。花名冊(cè)還包括一些用戶特殊的其它信息,比如用戶的昵稱,以及用戶所屬的群組。這些信息可以通過(guò)客戶端調(diào)用適當(dāng)接口顯示花名冊(cè)時(shí)顯現(xiàn)出來(lái)。
1.11. Jabber IDs Jabber代號(hào)
在Jabber里,有許多不同的實(shí)體需要進(jìn)行相互通信。這些實(shí)體可以表現(xiàn)為傳輸器、群組聊天室、或者是單一的Jabber用戶。Jabber IDs是內(nèi)外結(jié)合的表示用戶身份或路由信息。Jabber IDs的關(guān)鍵特性包括:
它們唯一確定進(jìn)行即時(shí)消息和在線信息狀態(tài)通信的獨(dú)立對(duì)象或?qū)嶓w
用戶很容易記住它們并在真實(shí)世界中進(jìn)行表達(dá)
它們很靈活,以至于可以包容其它IM和在線信息狀態(tài)表。
每一個(gè)Jabber ID(或JID)包括一套有序的元素。JIDs由域、節(jié)點(diǎn)、數(shù)據(jù)流格式的資源組成:
[node@]domain[/resource]
Jabber ID 元素有以下定義:
域名是第一標(biāo)識(shí)符。它表明實(shí)體連接的Jabber服務(wù)器。每一個(gè)可用的Jabber域名都應(yīng)擁有一個(gè)完整的域名。
節(jié)點(diǎn)是第二標(biāo)識(shí)符。它表明“用戶”本身。所有的節(jié)點(diǎn)都對(duì)應(yīng)一個(gè)精確的域。不過(guò),節(jié)點(diǎn)是可選的,一個(gè)精確的域(如conference.jabber.org)是非法Jabber ID。
資源是可選的第三標(biāo)識(shí)符。所有資源都屬于一個(gè)節(jié)點(diǎn)。在Jabber中,資源被用來(lái)識(shí)別屬于用戶的特殊對(duì)象,比如設(shè)備或位置。資源是一個(gè)單獨(dú)的用戶可以同時(shí)擁有幾個(gè)與同一Jabber服務(wù)器的連接;如:juliet@capulet.com/balcony vs. juliet@capulet.com/chamber.
一個(gè)Jabber用戶通常通過(guò)一個(gè)特殊的資源與服務(wù)器相連,因此在連接時(shí)有一個(gè)node@domain/resource形式的地址(如juliet@capulet.com/balcony)。由于資源時(shí)會(huì)話性的,用戶的地址可以和類似node@domain(如juliet@capulet.com)進(jìn)行通信,就象人們使用和它相同的形式的email一樣。
注意雖然在有些情況下,消息可以直接發(fā)送到一個(gè)精確資源,但總的來(lái)說(shuō),一個(gè)發(fā)往juliet@capulet.com消息根據(jù)Jabber服務(wù)器上的規(guī)則進(jìn)行路由,因?yàn)槊恳粋€(gè)連接實(shí)例都有它自己的優(yōu)先級(jí)設(shè)定。這樣,如果一條消息正好是發(fā)送給juliet@capulet.com(即沒有指定任一資源),該消息路由到擁有最高優(yōu)先級(jí)的資源,如:juliet@capulet.com/balcony。
1.12. Server Dialback 服務(wù)器回滾
1.2版的服務(wù)器增加了一個(gè)成為服務(wù)器回滾的功能。這個(gè)功能是設(shè)計(jì)用來(lái)服務(wù)器欺騙的,這樣就為服務(wù)器-服務(wù)器之間的交互增加了一個(gè)額外的安全方法。關(guān)于這個(gè)功能的詳細(xì)信息會(huì)在這個(gè)文檔的未來(lái)版本中提供。下面網(wǎng)址提供了一些初步的文檔:http://docs.jabber.org/draft-proto/html/dialback.html.