日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

Openfire配置過(guò)程,以及與php交互注意事項(xiàng)。

系統(tǒng) 3117 0

使用 XMPP 構(gòu)建一個(gè)基于 web 的通知工具 轉(zhuǎn)

使用 XMPP 構(gòu)建一個(gè)基于 web 的通知工具

使用 XMPP、PHP 和 JavaScript 編寫實(shí)時(shí) web 應(yīng)用程序

Ben Werdmuller , 顧問(wèn)和作者, Freelance

clip_image001

Ben Werdmuller 是一位 Web 策劃師和開(kāi)發(fā)人員,他專注于開(kāi)放源碼平臺(tái)。他是開(kāi)源社交網(wǎng)絡(luò)框架 Elgg 的共同創(chuàng)始人和技術(shù)帶頭人。Ben 的博客? http://benwerd.com/ 。

簡(jiǎn)介: ?實(shí)時(shí) web 應(yīng)用程序是聯(lián)網(wǎng)的應(yīng)用程序,帶有基于 web 的用戶界面,能夠及時(shí)顯示剛剛發(fā)布的 Internet 信息。這樣的應(yīng)用程序示例包括社會(huì)新聞聚合器和監(jiān)控工具,它們能夠使用來(lái)自外部源的數(shù)據(jù)持續(xù)更新。在本教程中,您將創(chuàng)建一個(gè)小型通知工具 Pingstream,它使用 PHP 和 JavaScript 通過(guò) Extensible Messaging and Presence Protocol (XMPP) 進(jìn)行通信,XMPP 是一組設(shè)計(jì)用于支持聯(lián)機(jī)狀態(tài)和實(shí)時(shí)通信功能的 XML 技術(shù)。

開(kāi)始之前

本教程將向您介紹實(shí)時(shí) web,并詳細(xì)介紹之所以要構(gòu)建實(shí)時(shí) web 應(yīng)用程序的幾個(gè)原因。您將學(xué)到一些技術(shù),這些技術(shù)將幫助您創(chuàng)建響應(yīng)及時(shí)、持續(xù)更新的 web 應(yīng)用程序,這些應(yīng)用程序既能保護(hù)服務(wù)器資源,又能提供良好的用戶體驗(yàn)。

關(guān)于本教程

常用縮略詞

DOM: 文檔對(duì)象模型

HTML: 超文本標(biāo)記語(yǔ)言

HTTP: 超文本傳輸協(xié)議

REST: 具象狀態(tài)傳輸

RSS: 真正簡(jiǎn)單聚合

URL: 統(tǒng)一資源定位符

XML: 可擴(kuò)展標(biāo)記語(yǔ)言

實(shí)時(shí) web 應(yīng)用程序允許用戶在信息發(fā)布時(shí)及時(shí)接收通知,無(wú)需手動(dòng)檢查原始源獲取更新。通過(guò) Twitter 和 Friendfeed 這樣的社交通知工具,Google Wave 這樣的基于 web 的協(xié)作工具,以及 Meebo 這樣的基于 web 的聊天客戶端,實(shí)時(shí) web 應(yīng)用程序逐漸流行起來(lái)。

Extensible Messaging and Presence Protocol (XMPP) 是一組基于 XML 的技術(shù),用于實(shí)時(shí)應(yīng)用程序,定義為持續(xù)更新以響應(yīng)新數(shù)據(jù)或更改數(shù)據(jù)的聯(lián)網(wǎng)應(yīng)用程序。它最初作為一個(gè)框架研發(fā),以支持企業(yè)環(huán)境內(nèi)的實(shí)時(shí)消息傳遞和聯(lián)機(jī)狀態(tài)(presence)應(yīng)用程序。

在本教程中,您將構(gòu)建一個(gè)簡(jiǎn)單的工具 Pingstream,它在 RSS 提要更新發(fā)布時(shí)使用它們持續(xù)更新自身(參見(jiàn)? 下載 ?獲取 Pingstream 源代碼)。在此過(guò)程中,您將:

了解 XMPP 為何特別適合 web 應(yīng)用程序;

了解 XMPP 通信的組件;

安裝和配置 Openfire XMPP 服務(wù)器;

使用 PHP 和 XMPPHP 庫(kù)連接到 XMPP 服務(wù)器;

檢查并通過(guò) XMPP 傳輸 RSS 提要中的新項(xiàng)目;

借助 Bidirectional-streams Over Synchronous HTTP (BOSH),使用 Strophe 和 jQuery 通過(guò) HTTP 連接到 XMPP 服務(wù)器;

在 web 頁(yè)面中顯示 XMPP 通知。


先決條件

本教程假定您比較熟悉使用 PHP 開(kāi)發(fā) web 應(yīng)用程序,但也會(huì)涉及一些高級(jí)編程方法。您還應(yīng)該擁有一定的 HTML 和 JavaScript 經(jīng)驗(yàn)。擁有 jQuery JavaScript 框架經(jīng)驗(yàn)可能會(huì)有所幫助。但本教程不要求熟悉 XMPP 或類似的技術(shù)。

要跟隨本教程操作,必須安裝和運(yùn)行以下服務(wù)器軟件:

PHP 5.2 或更高版本

Apache HTTP Server

MySQL

在本教程中,您還將下載和安裝以下軟件和庫(kù):

Openfire

jQuery

Strophe

XMPPHP

Last RSS

您可能會(huì)發(fā)現(xiàn) MySQL 服務(wù)器工具 phpMyAdmin 能夠派上用場(chǎng)。如果您使用一臺(tái)桌面機(jī)器來(lái)本地測(cè)試您的實(shí)時(shí) web 應(yīng)用程序,您可能會(huì)發(fā)現(xiàn) XAMPP 對(duì)于管理一個(gè)測(cè)試 web 服務(wù)器基礎(chǔ)設(shè)施的安裝和運(yùn)行很有用。

實(shí)時(shí) web 簡(jiǎn)介

在本小節(jié)中,您將了解什么是實(shí)時(shí) web 應(yīng)用程序,您為何可能需要構(gòu)建這樣的應(yīng)用程序,以及它們與典型的現(xiàn)代 web 應(yīng)用程序模型的區(qū)別何在。

接受輸入并提供反饋

實(shí)時(shí) web 并不實(shí)時(shí)

持續(xù)更新的 ?web? 應(yīng)用程序 ?這個(gè)詞匯比 實(shí)時(shí) ?web? 應(yīng)用程序 ?更貼切。在計(jì)算機(jī)科學(xué)中, ?和 ?實(shí)時(shí)系統(tǒng)都必須滿足操作期限的要求。當(dāng)任務(wù)不能在其分配時(shí)間內(nèi)完成時(shí),硬實(shí)時(shí)系統(tǒng)將失敗。實(shí)時(shí) web 應(yīng)用程序與軟實(shí)時(shí)系統(tǒng)更相似,在軟實(shí)時(shí)系統(tǒng)中,某個(gè)功能的延遲并不會(huì)導(dǎo)致系統(tǒng)失?。ǖ赡軙?huì)降低性能)。但您不應(yīng)對(duì)實(shí)時(shí) web 應(yīng)用程序分配嚴(yán)格的任務(wù)計(jì)劃。目前,web 并不是適合時(shí)間關(guān)鍵型應(yīng)用程序的平臺(tái)。

應(yīng)用程序是幫助用戶執(zhí)行任務(wù)的專門軟件,其特征是:從用戶或其他源接收輸入,然后提供可讀的輸出。應(yīng)用程序也可能動(dòng)態(tài)響應(yīng) — 以可視或編程方式 — 自動(dòng)接收的輸入數(shù)據(jù)中的變化。例如,當(dāng)包含特定關(guān)鍵字的新聞出現(xiàn)在一個(gè)新聞監(jiān)控應(yīng)用程序連接到的新聞專線中時(shí),該應(yīng)用程序可能會(huì)通知用戶。

由于 web 的起源是作為一個(gè)文檔服務(wù)平臺(tái),因此它沒(méi)有針對(duì)應(yīng)用程序優(yōu)化。HTML 非常適合表示和超鏈接文本內(nèi)容,但不適合創(chuàng)建動(dòng)態(tài)界面。web 應(yīng)用程序能夠接收和響應(yīng)用戶輸入,這要?dú)w功于 PHP 這樣的服務(wù)器端腳本語(yǔ)言與表單和 JavaScript 這樣的 web 輸入技術(shù)的結(jié)合。但是,要?jiǎng)?chuàng)建 自動(dòng) ?更新的界面,您必須克服一些障礙。這些障礙比較難以克服,因?yàn)闆](méi)有任何 web 技術(shù)在研發(fā)時(shí)考慮到這個(gè)功能。相比之下(以新聞監(jiān)控為例),桌名軟件無(wú)需刷新其界面就能夠?qū)⑼ㄖl(fā)送給用戶;桌面軟件可以持續(xù)更新自身。相反,web 則局限于基于頁(yè)面的模型。

然而,基于 web 的實(shí)時(shí)應(yīng)用程序還是可以實(shí)現(xiàn)的,而且它們的好處顯而易見(jiàn)。這樣的應(yīng)用程序包括企業(yè)聊天工具、聯(lián)網(wǎng)的實(shí)時(shí)文檔協(xié)作工具、以及搜索界面,它們能夠及時(shí)顯示新發(fā)布的內(nèi)容。


面向健壯的應(yīng)用程序開(kāi)發(fā)的 Web 技術(shù)

通常,web 應(yīng)用程序通過(guò)使用 Asynchronous JavaScript and XML (Ajax) 工具來(lái)模擬持續(xù)更新的界面。在這個(gè)模型中,應(yīng)用程序的 web 頁(yè)面中包含 JavaScript,它在后臺(tái)反復(fù)請(qǐng)求一個(gè)服務(wù)器回?fù)?。盡管 Ajax 應(yīng)用程序的響應(yīng)性在很多情況下都?jí)蛴?,但這種技術(shù)還是有一些缺陷。

Ajax 不能容忍不穩(wěn)定的 Internet 連接:一次臨時(shí)掉線可能會(huì)導(dǎo)致整個(gè)界面失敗。它在服務(wù)器負(fù)載方面也效率低下。假設(shè)您的后臺(tái) Ajax 輪詢函數(shù)每 10 秒檢查一次服務(wù)器。每一次都將建立一個(gè)新的 HTTP 連接,包括初始化服務(wù)請(qǐng)求所需的資源,即使沒(méi)有新數(shù)據(jù)可以向用戶顯示。結(jié)果是應(yīng)用程序不必要地使用過(guò)多的處理器時(shí)間和帶寬。

基于 XML 的技術(shù)向 web 應(yīng)用程序提供了巨大的優(yōu)勢(shì)。XML 解析器現(xiàn)在是大多數(shù)環(huán)境的一個(gè)標(biāo)準(zhǔn)組成部分;無(wú)需其他軟件就能支持以適當(dāng)?shù)母袷阶x寫數(shù)據(jù)。XML 是自我描述型語(yǔ)言;使用它的文檔不需要外部架構(gòu)。最后,正如 web 是獨(dú)立于平臺(tái)的一樣,XML 作為一種技術(shù)支持在不同平臺(tái)間互操作。因此,開(kāi)發(fā)人員可以將精力集中于特定于他們的應(yīng)用程序的邏輯。

web 基于 HTML、Cascading Style Sheets (CSS) 和 JavaScript 等可互操作的免費(fèi)開(kāi)源標(biāo)準(zhǔn)。如果針對(duì) web 上的實(shí)時(shí)通信的新標(biāo)準(zhǔn)出現(xiàn),那么該標(biāo)準(zhǔn)也應(yīng)是免費(fèi)、開(kāi)源和可互操作的。基于 XML 的 XMPP 滿足這些標(biāo)準(zhǔn)。在本教程中,您將使用 XMPP 來(lái)構(gòu)建一個(gè)客戶端庫(kù),它通過(guò)標(biāo)準(zhǔn)方法(比如一個(gè) web hook)來(lái)接收輸入,并將適當(dāng)?shù)臄?shù)據(jù)實(shí)時(shí)中繼到用戶。

XMPP 簡(jiǎn)介

本小節(jié)將簡(jiǎn)要介紹 XMPP,它的起源,以及為何它是一個(gè)適合實(shí)時(shí) web 通信的協(xié)議。您將檢查 XMPP 通信設(shè)置的組件,并查看展示這些組件如何使用的示例。

Web 標(biāo)準(zhǔn)和 XMPP

XMPP 是一組基于 XML 的技術(shù),用于實(shí)時(shí)應(yīng)用程序。最初,XMPP 作為一個(gè)框架開(kāi)發(fā),目標(biāo)是支持企業(yè)環(huán)境內(nèi)的即時(shí)消息傳遞和聯(lián)機(jī)狀態(tài)應(yīng)用程序。當(dāng)時(shí)的即時(shí)消息傳遞網(wǎng)絡(luò)是私有的,非常不適合企業(yè)使用。例如,AOL Instant Messenger 不能針對(duì)公司內(nèi)的安全通信進(jìn)行調(diào)整。盡管存在一些商業(yè)解決方案,但它們固定的特性集通常不能進(jìn)行調(diào)整,以滿足組織的特殊需求。XMPP,當(dāng)時(shí)名為 Jabber,允許組織構(gòu)建自己的定制工具來(lái)促進(jìn)實(shí)時(shí)通信,并允許安裝現(xiàn)成的第三方解決方案。

XMPP 是一個(gè)分散型通信網(wǎng)絡(luò),這意味著,只要網(wǎng)絡(luò)基礎(chǔ)設(shè)施允許,任何 XMPP 用戶都可以向其他任何 XMPP 用戶傳遞消息。多個(gè) XMPP 服務(wù)器也可以通過(guò)一個(gè)專門的 “服務(wù)器-服務(wù)器” 協(xié)議相互通信,提供了創(chuàng)建分散型社交網(wǎng)絡(luò)和協(xié)作框架的有趣可能性,但這個(gè)主題已超出了本教程的討論范圍。

顧名思義,XMPP 可用于滿足廣泛的、對(duì)時(shí)間敏感的特性要求。實(shí)際上,Google Wave,一個(gè)大型多用戶協(xié)作環(huán)境,將 XMPP 作為其聯(lián)合協(xié)議的基礎(chǔ)。盡管 XMPP 的出現(xiàn)是為了滿足 “個(gè)人-個(gè)人” 即時(shí)消息傳遞的要求,但它完全不必局限于此任務(wù)。

XMPP 通信的結(jié)構(gòu)

要促進(jìn)消息傳遞,每個(gè) XMPP 客戶端用戶必須擁有一個(gè)全局惟一標(biāo)識(shí)符?;跉v史原因,這些標(biāo)識(shí)符稱為 Jabber IDs,或稱為 JIDs。鑒于這個(gè)協(xié)議的分布式特征,重要的是 JID 應(yīng)包含聯(lián)系用戶所需的所有信息:不存在將用戶鏈接到他們連接到的服務(wù)器的中央知識(shí)庫(kù)。JID 的結(jié)構(gòu)類似于電子郵件地址(但不要求 JID 同時(shí)也是有效的電子郵件收件人)。

客戶端和服務(wù)器節(jié)點(diǎn),我將它們統(tǒng)稱為? XMPP? 實(shí)體 ,都擁有 JIDs。SomeCorp 公司的員工 John Doe 可能擁有 JID John.Doe@somecorp.com。這里,somecorp.com 是 SomeCorp 公司的 XMPP 服務(wù)器的地址,John.Doe 是 John Doe 的用戶名。

JIDs 還擁有連接到它們的資源。這允許在一個(gè) XMPP 實(shí)體標(biāo)識(shí)符之外進(jìn)一步處理細(xì)粒度;例如,盡管上面的示例總體上能夠表示 John Doe,但 John.Doe@somecorp.com/Work 可以用于將數(shù)據(jù)發(fā)送到與他的工作相關(guān)的工具。

這些資源可以采用任意用戶定義的名稱,一個(gè) XMPP 實(shí)體可以擁有任意數(shù)量的資源。除了可以是上下文依賴的外,它們還可以綁定到設(shè)備、工具或工作站。對(duì)于您的 Pingstream 示例,web 站點(diǎn)的每個(gè)訪問(wèn)者都將作為同一個(gè)用戶登錄 XMPP 服務(wù)器,但他們擁有不同的資源。

通信類別

使用 XMPP 的實(shí)時(shí)消息傳遞系統(tǒng)包含三大通信類別:

消息傳遞,其中數(shù)據(jù)在有關(guān)各方之間傳輸;

聯(lián)機(jī)狀態(tài),它允許用戶廣播其在線狀態(tài)和可用性;

信息/查詢請(qǐng)求,它允許 XMPP 實(shí)體發(fā)起請(qǐng)求并從另一個(gè)實(shí)體接收響應(yīng)。

這些類別是互補(bǔ)的。例如,如果用戶或?qū)嶓w離線(盡管在許多用例中,理想的狀態(tài)是服務(wù)器在用戶返回之前一直持有用戶的消息),則沒(méi)有將數(shù)據(jù)發(fā)送給用戶或發(fā)起一個(gè)實(shí)體的信息/查詢請(qǐng)求的點(diǎn)。這些消息中的每一條都將通過(guò)一個(gè)完整的 XML? 節(jié) ?傳遞 — XML 節(jié)是以 XML 表達(dá)的獨(dú)立信息項(xiàng)。

這三種類型的 XMPP 節(jié)都擁有以下公共屬性:

from:源 XMPP 實(shí)體的 JID;

to:目標(biāo)接收者的 JID;

id:這次對(duì)話的可選標(biāo)識(shí)符;

type:節(jié)的可選子類型;

xml:lang:如果內(nèi)容是人們可讀的,則為消息語(yǔ)言的描述。

基于 XMPP 的數(shù)據(jù)傳輸發(fā)生在一些 XML 流上,默認(rèn)在端口 5222 上操作。這些 XML 流實(shí)際上是兩個(gè)完整的 XML 文檔,每個(gè)文檔對(duì)應(yīng)一個(gè)通信方向。一旦會(huì)話建立,stream 元素將打開(kāi)。這個(gè)元素將封裝整個(gè)通信文檔。然后,一些節(jié)被注入這個(gè)文檔的第二層。最后,一旦通信結(jié)束,stream 元素將關(guān)閉,形成一個(gè)完整的文檔。

例如, 清單 1 ?展示了一個(gè) stream 元素,它建立了從客戶端到服務(wù)器的通信。

清單 1.? 建立從客戶端到服務(wù)器的通信的 stream? 標(biāo)記

<stream:stream from="[server]" id="[unique ID over conversation]"

xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">


消息

一旦通信建立,客戶端就能使用 message 元素將消息發(fā)送到另一個(gè)用戶,message 元素包含以下任意子元素:

subject:一個(gè)可讀的字符串,表示消息主題。

body:一個(gè)可讀的字符串,表示消息體。如果每個(gè)消息體標(biāo)記都擁有一個(gè)不同的 xml:lang 值,那么可以包含多個(gè)消息體標(biāo)記。(xml:lang 是惟一可能的屬性。)

thread:一個(gè)惟一標(biāo)識(shí)符,表示一個(gè)消息線程??蛻舳塑浖梢允褂眠@個(gè)子元素將相關(guān)消息串聯(lián)在一起。

但是,消息也可以非常簡(jiǎn)單,如? 清單 2 ?所示:

清單 2.? 樣例消息

<message from="sendinguser@somedomain" to="recipient@somedomain" xml:lang='en'>

<body>

Body of message

</body>

</message>

對(duì)于提供實(shí)時(shí) web 界面而言,消息節(jié)是最有用的節(jié)。“發(fā)布-訂閱” 模型 — 在實(shí)時(shí) web 應(yīng)用程序中使用消息來(lái)傳輸數(shù)據(jù)的一種替代方法 — 將稍后介紹。


信息/查詢

信息/查詢節(jié)擁有廣泛的功能。一個(gè)例子就是 “發(fā)布-訂閱” 模型,在該模型中,發(fā)布者通知服務(wù)器某個(gè)特定資源進(jìn)行了更新,服務(wù)器則通知已選擇訂閱這些通知并擁有適當(dāng)授權(quán)的所有 XMPP 用戶。

來(lái)自發(fā)布者的一系列項(xiàng)目被編碼為一些節(jié),格式為基于 XML 的 Atom 發(fā)布格式。每個(gè)項(xiàng)目都包含在一個(gè) item 元素內(nèi),然后合并到一個(gè) pubsub 元素中,最后成為一個(gè)信息/查詢節(jié)。在? 清單 3 (選自 XMPP 發(fā)布-訂閱規(guī)范)中,Shakespeare's Hamlet(JID 為 hamlet@denmark.lit/blogbot)用他著名的獨(dú)白發(fā)布一個(gè)更新到 pubsub.shakespeare.lit pubsub 更新節(jié)點(diǎn):

清單 3.? 對(duì) pubsub.shakespeare.lit pubsub? 更新節(jié)點(diǎn)的更新

<iq type="set"

from="hamlet@denmark.lit/blogbot"

to="pubsub.shakespeare.lit"

id="pub1">

<pubsub xmlns="http://jabber.org/protocol/pubsub">

<publish node="princely_musings">

<item>

<entry xmlns="http://www.w3.org/2005/Atom">

<title>Soliloquy</title>

<summary>

To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?

</summary>

<link rel="alternate" type="text/html"

/>

<id>tag:denmark.lit,2003:entry-32397</id>

<published>2003-12-13T18:30:02Z</published>

<updated>2003-12-13T18:30:02Z</updated>

</entry>

</item>

</publish>

</pubsub>

</iq>

信息/查詢節(jié)也用于請(qǐng)求一個(gè)特定 XMPP 實(shí)體的有關(guān)信息。例如,在? 清單 4 ?中的節(jié)中,boreduser@somewhere 正在查找 friendlyuser@somewhereelse 擁有的公共項(xiàng)目。

清單 4.? 用戶查找由 friendlyuser@somewhereelse? 擁有的公共項(xiàng)目

<iq type="get"

from="boreduser@somewhere"

to="friendlyuser@somewhereelse"

id="publicStuff">

<query xmlns="http://jabber.org/protocol/disco#items"/>

</iq>

反過(guò)來(lái),friendlyuser@somewhereelse 使用一列可被訂閱到使用 “發(fā)布-訂閱” 的項(xiàng)目進(jìn)行響應(yīng),如? 清單 5 ?所示:

清單 5.? 使用一列項(xiàng)目響應(yīng)

<iq type="result"

from="friendlyuser@somewhereelse"

to="boreduser@somewhere"

id="publicStuff">

<query xmlns="http://jabber.org/protocol/disco#items">

<item jid="stuff.to.do"

name="Things to do"/>

<item jid="stuff.to.not.do"

name="Things to avoid doing"/>

</query>

</iq>

在? 清單 5 ?中的信息/查詢節(jié)中的每個(gè)返回項(xiàng)目都擁有一個(gè)可以訂閱到的 JID。信息/查詢還允許超出本教程范圍的廣泛的服務(wù)器信息請(qǐng)求。它們中的許多在針對(duì)多服務(wù)器環(huán)境的 web 應(yīng)用程序上下文中有用,或者作為復(fù)雜的分散型協(xié)作框架的基礎(chǔ)。


聯(lián)機(jī)狀態(tài)

聯(lián)機(jī)狀態(tài)信息包含在一個(gè)聯(lián)機(jī)狀態(tài)(presence)節(jié)中。如果 type 屬性省略,那么 XMPP 客戶端應(yīng)用程序假定用戶在線且可用。否則,type 可設(shè)置為 unavailable,或者特定于 pubsub 的值:subscribe、subscribed、unsubscribe 和 unsubscribed。它也可以是針對(duì)另一個(gè)用戶的聯(lián)機(jī)狀態(tài)信息的一個(gè)錯(cuò)誤或探針。

一個(gè)聯(lián)機(jī)狀態(tài)節(jié)可以包含以下子元素:

show:一個(gè)機(jī)器可讀的值,表示要顯示的在線狀態(tài)的總體類別。這可以是 away(暫時(shí)離開(kāi))、chat(可用且有興趣交流)、dnd(請(qǐng)勿打擾)、或 xa(長(zhǎng)時(shí)間離開(kāi))。

status:一個(gè)可讀的 show 值。該值為用戶可定義的字符串。

priority:一個(gè)位于 -128 到 127 之間的值,定義消息路由到用戶的優(yōu)先順序。如果值為負(fù)數(shù),用戶的消息將被扣留。

例如, 清單 6 ?中的 boreduser@somewhere 可以用這個(gè)節(jié)來(lái)表明聊天意愿:


清單 6.? 樣例聯(lián)機(jī)狀態(tài)通知

<presence xml:lang="en">

<show>chat</show>

<status>Bored out of my mind</status>

<priority>1</priority>

</presence>

注意 from 屬性此處省略。

另一個(gè)用戶 friendlyuser@somewhereelse 可以通過(guò)發(fā)送? 清單 7 ?中的節(jié)來(lái)探測(cè) boreduser@somewhere 的狀態(tài):

清單 7.? 探測(cè)用戶狀態(tài)

<presence type="probe" from="friendlyuser@somewhereelse" to="boreduser@somewhere"/>

Boreduser@somewhere's server would then respond with a tailored presence response:

<presence xml:lang="en" from="boreduser@somewhere" to="friendlyuser@somewhereelse">

<show>chat</show>

<status>Bored out of my mind</status>

<priority>1</priority>

</presence>

這些聯(lián)機(jī)狀態(tài)值源自 “個(gè)人-個(gè)人” 消息傳遞軟件。show 元素的值 — 通常用于確定將向其他用戶顯示的狀態(tài)圖標(biāo) — 在聊天應(yīng)用程序之外如何使用現(xiàn)在還不清楚。狀態(tài)值可能會(huì)在微博工具中找到用武之地;例如,Google Talk(一個(gè) XMPP 聊天服務(wù))中的用戶狀態(tài)字段的更改可以被導(dǎo)入為 Google Buzz 中的微博條目。

另一種可能性就是將狀態(tài)值用作每用戶應(yīng)用程序狀態(tài)數(shù)據(jù)的攜帶者。盡管此規(guī)范將狀態(tài)定義為可讀,但沒(méi)有什么能夠阻止您在那里存儲(chǔ)任意字符串來(lái)滿足您的要求。對(duì)于某些應(yīng)用程序而言,它可以不是可讀的,或者,它可以攜帶微格式形態(tài)的數(shù)據(jù)負(fù)載。

您可以為一個(gè) XMPP 實(shí)體擁有的每個(gè)資源獨(dú)立設(shè)置聯(lián)機(jī)狀態(tài)信息,以便訪問(wèn)和接收連接到一個(gè)應(yīng)用程序中的單個(gè)用戶的所有工具和上下文的數(shù)據(jù)只需一個(gè)用戶帳戶。每個(gè)資源都可以被分配一個(gè)獨(dú)立的優(yōu)先級(jí);XMPP 服務(wù)器將首先嘗試將消息傳遞給優(yōu)先級(jí)較高的資源。


XMPP 使用 BOSH 越過(guò) HTTP

要通過(guò)使用 JavaScript 的 XMPP 進(jìn)行通信的 web 應(yīng)用程序必須符合一些特殊要求。出于安全考慮,不允許 JavaScript 從 web 頁(yè)面的域與不同域上的多個(gè)服務(wù)器通信。如果您的 web 應(yīng)用程序界面被托管在 application.mydomain.com,所有 XMPP 通信也必須發(fā)生在 application.mydomain.com。

防火墻是另一個(gè)問(wèn)題所在。理想情況下,如果您將 XMPP 用作您的 web 界面的實(shí)時(shí)元素的基礎(chǔ),那么您希望它對(duì)防火墻后面的用戶有效。但是,公司防火墻通常只對(duì)少數(shù)幾個(gè)協(xié)議開(kāi)放幾個(gè)端口,以便允許 web 數(shù)據(jù)、電子郵件和類似的通信通過(guò)。默認(rèn)情況下,XMPP 使用端口 5222,這很可能是公司防火墻阻止的端口。

假設(shè)您知道您的用戶前面的防火墻在端口 80 上允許 HTTP(這是用于訪問(wèn) web 的默認(rèn)協(xié)議和端口)。理想情況是您的 XMPP 通信能夠越過(guò)該端口上的 HTTP。但是,HTTP 的設(shè)計(jì)并不針對(duì)持續(xù)連接。web 的架構(gòu)不同于實(shí)時(shí)數(shù)據(jù)所需的通信架構(gòu)。

下面我們看看 Bidirectional-streams Over Synchronous HTTP (BOSH) 的標(biāo)準(zhǔn),該標(biāo)準(zhǔn)為雙向同步數(shù)據(jù)提供一個(gè)模擬層。借助這個(gè)標(biāo)準(zhǔn),可以與一個(gè) XMPP 服務(wù)器建立一個(gè)較長(zhǎng)的 HTTP 連接(時(shí)長(zhǎng)一分鐘或兩分鐘)。如果新數(shù)據(jù)在那個(gè)期間到達(dá),則 HTTP 請(qǐng)求返回?cái)?shù)據(jù)并關(guān)閉;否則,該請(qǐng)求只是失效。不管是哪種情況,一旦一個(gè)請(qǐng)求關(guān)閉,另一個(gè)請(qǐng)求將重新建立。盡管結(jié)果是對(duì)一個(gè) web 服務(wù)器的一系列重復(fù)連接,但它是一個(gè)比 Ajax 輪詢更有效的數(shù)量級(jí),特別是因?yàn)檫B接到的是一個(gè)專業(yè)服務(wù)器而不是直接連接到 web 應(yīng)用程序。

BOSH 上的 XMPP 允許 web 應(yīng)用程序通過(guò)一個(gè)原生連接持續(xù)與 XMPP 服務(wù)器通信??蛻舳送ㄟ^(guò)端口 80 上的 HTTP 上的一個(gè)標(biāo)準(zhǔn) URL 連接。然后,web 服務(wù)器將這個(gè)連接代理到由 XMPP 服務(wù)器操作的一個(gè)不同端口 — 通常是 7070 — 上的 HTTP URL。這樣,無(wú)論何時(shí)數(shù)據(jù)被發(fā)送到 XMPP 服務(wù)器,web 應(yīng)用程序只需使用一些資源,而 web 客戶端可以使用通常支持的 web 標(biāo)準(zhǔn)從防火墻后操作。維持 BOSH 的較長(zhǎng) HTTP 輪詢的開(kāi)銷主要由 XMPP 服務(wù)器而不是 web 服務(wù)器或 web 應(yīng)用程序承擔(dān)。web 服務(wù)器和 XMPP 服務(wù)器都不會(huì)受到與使用 JavaScript 進(jìn)行通信一樣的域限制,正是因?yàn)檫@一點(diǎn),消息才能夠被發(fā)送到其他 XMPP 服務(wù)器和客戶端。

現(xiàn)在,您理解了 XMPP 如何適合實(shí)時(shí) web,可以下載并設(shè)置它,以便開(kāi)始創(chuàng)建這個(gè) Pingstream 應(yīng)用程序。

獲取和安裝一個(gè) XMPP 服務(wù)器

在本小節(jié)中,您將安裝 Openfire XMPP 服務(wù)器并配置它來(lái)支持您的實(shí)時(shí) web 應(yīng)用程序。

選擇一個(gè) XMPP 服務(wù)器

有兩個(gè)領(lǐng)先的開(kāi)源 XMPP 服務(wù)器可以免費(fèi)下載。它們都應(yīng)用廣泛并通過(guò) GNU Public License version 2 許可,每個(gè)服務(wù)器都有自己的優(yōu)勢(shì)和缺點(diǎn):

l ejabberd:ejabberd 中的? e ?指的是 Erlang,一種軟實(shí)時(shí)編程語(yǔ)言。這一技術(shù)基石使 ejabberd 非常快。它還與 XMPP 核心和相關(guān)標(biāo)準(zhǔn)高度兼容。ejabberd 可以安裝在大多數(shù)環(huán)境中。

l Openfire:Openfire 用 Java? 語(yǔ)言編寫,用戶友好,安裝方便。

本教程使用 Openfire。


創(chuàng)建 Openfire 數(shù)據(jù)庫(kù)

為您的 Openfire 用戶和配置創(chuàng)建一個(gè)新的 MySQL 數(shù)據(jù)庫(kù)。通過(guò)使用 MySQL,您可以以編程方式從您的 PHP web 應(yīng)用程序添加、編輯、刪除和查詢您的 XMPP 服務(wù)器用戶,以及調(diào)節(jié)您的 XMPP 基礎(chǔ)設(shè)施以匹配您的 web 基礎(chǔ)設(shè)施。

如果您安裝了 phpMyAdmin,比如作為您的 XAMPP 安裝的一部分,那么您可以按照以下步驟創(chuàng)建數(shù)據(jù)庫(kù):

1. 從主界面選擇? Privileges 。

2. 選擇? Add a new user 。

3. 添加用戶細(xì)節(jié)(確保主機(jī)是 localhost;本教程假定您是在 localhost 上測(cè)試),選擇? Create database with same name and grant all privileges ,如? 圖 1 ?所示。不要向您的 Openfire 數(shù)據(jù)庫(kù)新用戶授予全局?jǐn)?shù)據(jù)庫(kù)特權(quán)。

圖 1. 在 phpMyAdmin 中添加一個(gè) Openfire 數(shù)據(jù)庫(kù)?
clip_image002

添加用戶和數(shù)據(jù)庫(kù)后,就可以安裝 Openfire 服務(wù)器了。


安裝 Openfire

下載 Openfire 安裝程序并運(yùn)行它,將 Openfire 安裝到您選擇的位置(參見(jiàn)? 參考資料 )。(您也可以選擇從 Openfire 的 Subversion 源代碼知識(shí)庫(kù)檢查 Openfire 的最新版本并本地構(gòu)建它,但這個(gè)主題超出了本教程的范圍。)收到提示時(shí),告知 Openfire 安裝程序在安裝完成時(shí)啟動(dòng)服務(wù)器。

服務(wù)器啟動(dòng)后,您應(yīng)該看到服務(wù)器狀態(tài)窗口,如? 圖 2 ?所示:

圖 2. Openfire? 的狀態(tài)窗口 ?
clip_image003

單擊? Launch Admin ?打開(kāi)一個(gè)基于 web 的向?qū)?,? 圖 3 ?所示,該向?qū)鸩脚渲媚?Openfire 服務(wù)器:

圖 3.? 配置向?qū)? ?
clip_image004

配置向?qū)г试S您選擇使用標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)連接或嵌入式數(shù)據(jù)庫(kù)連接。選擇標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)連接,以便您能夠使用您的 MySQL 數(shù)據(jù)庫(kù)。

從? Database Driver Presets ?列表選擇 MySQL。將您的服務(wù)器和數(shù)據(jù)庫(kù)名稱插入? Database URL ?字段。例如,對(duì)于在 localhost 上設(shè)置、名為 openfire 的 MySQL 數(shù)據(jù)庫(kù)而言,應(yīng)輸入:

jdbc:mysql://localhost:3306/openfire

在向?qū)У南乱黄聊簧?,選擇將用戶帳戶存儲(chǔ)在數(shù)據(jù)庫(kù)中。輸入此前創(chuàng)建的數(shù)據(jù)庫(kù)用戶的用戶名和密碼,然后一直繼續(xù)到配置向?qū)ЫY(jié)束。此時(shí),您應(yīng)該已經(jīng)為您的 XMPP 服務(wù)器創(chuàng)建了一個(gè)服務(wù)器管理員并設(shè)置了域位置。

每用戶通知的插件

根據(jù)本教程的演示目的,您將只需使用在這里創(chuàng)建的兩個(gè)用戶。但是,如果您希望在您的應(yīng)用程序中支持復(fù)雜的每用戶通知,那么您需要能夠以編程方式從您的應(yīng)用程序的 PHP 部分添加和移除用戶。Openfire 的 User Service 插件通過(guò)一個(gè)用于 XMPP 用戶管理的 REST 界面向您提供這個(gè)功能。要安裝這個(gè)插件,從 Openfire 插件站點(diǎn)(參見(jiàn)? 參考資料 )下載它。插件本身是單個(gè)文件:userservice.jar。您必須將其放置到您的 Openfire 安裝的 /plugins 目錄中。

使用您建立的管理員憑證登錄到管理屏幕。單擊? Edit Properties (位于? Server ports ?下方),記錄列示的服務(wù)器名稱。這個(gè)名稱將形成您的 JIDs 的域部分。這個(gè)名稱是不可互換的,比如,不能使用? localhost ?替代? 127.0.0.1 ,反之也不行。

單擊頂部導(dǎo)航菜單中的? Users/Groups ?并創(chuàng)建兩個(gè)新用戶。這些用戶將您在開(kāi)發(fā)過(guò)程中的測(cè)試用戶。

單擊? Server settings ,然后單擊? Offline messages 。由于您將 XMPP 用于界面通知,因此應(yīng)將? Offline Message Policy ?設(shè)置為? Drop ,如? 圖 4 ?所示。您不想保存用戶沒(méi)有登錄時(shí)收到的消息,否則,當(dāng)他們返回時(shí),可能會(huì)被數(shù)千條通知所 “淹沒(méi)”。

圖 4. 丟棄離線消息?
clip_image005

在? Server settings ?中,單擊? Server to Server 。對(duì)于本文,您不必連接到外部服務(wù)器,因?yàn)槟恍枰鳛楦蟮?XMPP 網(wǎng)絡(luò)的一個(gè)連接部分操作。因此,將? Service Enabled ?設(shè)置為? Disabled , Allowed to Connect ?設(shè)置為? White List 。這些設(shè)置將阻止未授權(quán)的連接造成破壞。


配置 Apache 以通過(guò) BOSH 轉(zhuǎn)發(fā) XMPP

Openfire 在 http://localhost:7070/http-bind 維護(hù)了一個(gè) HTTP 綁定 URL,以便通過(guò) BOSH 訪問(wèn)。要在端口 80 上使用這個(gè) URL,您必須配置 Apache HTTP Server 以將一個(gè) URL 轉(zhuǎn)發(fā)到這個(gè)位置。為此,您需要啟動(dòng)代理模塊。

打開(kāi)您的 http.conf Apache 配置文件并找到? mod_proxy.so 和? mod_proxy_http.so ?的? LoadModule ?條目,它們默認(rèn)被注釋掉。移除前導(dǎo)的井字符( # ),取消注釋。這個(gè)配置文件的 Dynamic Shared Object (DSO) Support 部分中的多個(gè)適當(dāng)?shù)男校ú灰欢ㄔ谝黄穑┈F(xiàn)在應(yīng)該類似于? 清單 8

清單 8.? 啟用 Apache HTTP Server? 中的代理支持

LoadModule proxy_http_module modules/mod_proxy_http.so

LoadModule proxy_module modules/mod_proxy.so

在配置文件的末尾,添加? 清單 9 ?中的行(如果您沒(méi)有將 locahost 作為您的測(cè)試服務(wù)器環(huán)境,則應(yīng)將 127.0.0.1 替換為您的服務(wù)器 IP 地址):

清單 9. httpd.cof? 中的 XMPP? 代理規(guī)則

# XMPP proxy rule

ProxyRequests Off

ProxyPass /xmpp-httpbind http://127.0.0.1:7070/http-bind/

ProxyPassReverse /xmpp-httpbind http://127.0.0.1:7070/http-bind/

注意,在? 清單 9 ?中,您在端口 80 上使用了一個(gè)稍微不同的 URL: /xmpp-httpbind 。這個(gè) URL 是 strophe.js(您稍后將用到的客戶端 JavaScript 框架)分配給一個(gè)用于設(shè)置 BOSH 端點(diǎn)的變量的值。

重啟服務(wù)器。現(xiàn)在,您可以開(kāi)始編寫使用 XMPP 的 web 應(yīng)用程序了。

創(chuàng)建使用 XMPPHP 的服務(wù)器應(yīng)用程序

在前面的小節(jié)中,您設(shè)置了服務(wù)器和插件。在本小節(jié)中,您將創(chuàng)建您的實(shí)時(shí)應(yīng)用程序的服務(wù)器端部分。

服務(wù)器端功能

您的應(yīng)用程序的 PHP 端將執(zhí)行以下兩個(gè)主要任務(wù):

1. 一個(gè) PHP 腳本將獲取一個(gè) RSS,并將在第一個(gè)條目自您上次檢查以來(lái)發(fā)生改變時(shí)通知您。

2. 一個(gè)前端腳本將初始化您的 JavaScript XMPP 客戶端。

首先在您的測(cè)試服務(wù)器的 web 根中創(chuàng)建一個(gè)名為 pingstream 的 PHP 新項(xiàng)目空間。如果您使用針對(duì) Eclipse 開(kāi)發(fā)環(huán)境的 PHP Development Tools 項(xiàng)目擴(kuò)展,那么要注意,要在 web 根、而不是 Eclipse 的默認(rèn)工作空間中創(chuàng)建這個(gè)項(xiàng)目(參見(jiàn)? 圖 5 ):

圖 5. 創(chuàng)建一個(gè)新的 Eclipse PHP 項(xiàng)目?
clip_image006

圖 5 ?顯示了這個(gè) Pingstream 項(xiàng)目的以下值:

l Project name 字段:Pingstream

l Contents 單選按鈕:Create project from existing source

l Directory 字段:c:\xampp\htdocs\pingsstream

l PHP Version 單選按鈕:Use default PHP settings

XMPPHP 是應(yīng)用最廣泛的針對(duì) PHP 的 XMPP 庫(kù)。與 ejabberd 和 Openfire 一樣,它也是免費(fèi)和開(kāi)源的,因此它是首次使用 XMPP 開(kāi)發(fā)人員的一個(gè)不錯(cuò)的起點(diǎn)。

下載 XMPPHP(參見(jiàn)? 參考資料 )。解包這個(gè)歸檔并將其插入您的新項(xiàng)目的 lib/xmpphp 子文件夾中。

最后,為節(jié)約您的 RSS 提要的解析時(shí)間,下載并安裝 Last RSS PHP 解析器(參見(jiàn)? 參考資料 )。


存儲(chǔ)服務(wù)器端設(shè)置

您將使用此前創(chuàng)建的兩個(gè)測(cè)試用戶之一作為您的通知發(fā)送方。在您的 /pingstream 的根中創(chuàng)建一個(gè)名為 config.inc.php 的文件,并添加? 清單 10 ?中的內(nèi)容:

清單 10.? 服務(wù)器端配置設(shè)置

<?php

// Pingstream configuration file

// Define global $CONFIG array - don't change this!

global $CONFIG;

$CONFIG = array();

$CONFIG['send'] = new stdClass();

// Set account details for sending party

$CONFIG['send']->user = 'testuser'; // User portion of JID

$CONFIG['send']->host = '127.0.0.1'; // Host portion of JID

$CONFIG['send']->resc = 'pingstream';// Resource portion of JID

$CONFIG['send']->pass = 'mypass'; // Password for user

config.inc.php 文件還必須包含關(guān)于您的接收方的細(xì)節(jié),如? 清單 11 ?所示:

清單 11. 關(guān)于接收方的細(xì)節(jié)

// Set the receiving account details

$CONFIG['receive'] = 'receivinguser@127.0.0.1';

您還需將少量數(shù)據(jù)緩存在一個(gè)文件中,因此 config.inc.php 需要包含一個(gè)可寫入的文件路徑,如? 清單 12 ?所示:

清單 12.? 設(shè)置存儲(chǔ)臨時(shí)文件的位置

// Full path to your cache directory, with trailing slash

$CONFIG['cachedir'] = '/tmp/';

如果您位于一臺(tái) Microsoft? Windows? 機(jī)器上,那么您可以將這個(gè)位置設(shè)置為一個(gè)空字符串。否則,確保您指定的目錄包含一個(gè)完整路徑和一個(gè)結(jié)束斜杠,并被設(shè)置為全局可寫入(world-writeable)。


定義數(shù)據(jù)源

您的 Pingstream 應(yīng)用程序?qū)z查 IBM developerWorks Web development 專區(qū)提要獲取更新,因此,將? 清單 13 ?中的內(nèi)容添加到 config.inc.php:

清單 13. 檢查一個(gè) developerWorks 提要獲取更新

// Set the RSS feed you're going to check

$CONFIG['rss'] = 'http://www.ibm.com/developerworks/views/web/rss/libraryview.jsp';

現(xiàn)在,創(chuàng)建另一個(gè)新文件:/lib.inc.php。這將是您的庫(kù)文件,包含在您的應(yīng)用程序的主控制器頁(yè)面和用戶界面頁(yè)面中。

lib.inc.php 的頂端必須引用 config.inc.php(主 XMPPHP 庫(kù))和 lastRSS,如? 清單 14 ?所示:

清單 14. 加載必要的庫(kù)

<?php

// Load libraries

require_once('XMPPHP/XMPP.php');

require_once('config.inc.php');

require_once('lastRSS.php');

接下來(lái),您將創(chuàng)建一個(gè)函數(shù)來(lái)通過(guò) XMPP 將一條消息發(fā)送到客戶端。通過(guò) XMPPHP 完成這個(gè)任務(wù)很簡(jiǎn)單,只需使用在您的配置文件中保存的憑證建立一個(gè)連接,發(fā)送消息,然后關(guān)閉連接。

在這個(gè)函數(shù)的第一部分中,您創(chuàng)建了一個(gè)新的 XMPPHP_XMPP 對(duì)象,如? 清單 15 ?所示:

清單 15. 創(chuàng)建一個(gè)新的 XMPP 連接對(duì)象

// Load configuration

global $CONFIG;

$conn = new XMPPHP_XMPP(

$CONFIG['connect']->host,

5222,

$CONFIG['connect']->user,

$CONFIG['connect']->pass,

$CONFIG['connect']->resc);

注意,XMPPHP 通過(guò) XMPP 通信的默認(rèn)端口 5222 連接到您的 XMPP 服務(wù)器。盡管您的客戶端通信需要使用 BOSH,但服務(wù)器端沒(méi)有這個(gè)要求。

要連接到 XMPP 服務(wù)器,需要發(fā)送一個(gè)初始連接請(qǐng)求,一直等到接收到您的 XMPP 會(huì)話已經(jīng)啟動(dòng)的通知,然后發(fā)送一個(gè)聯(lián)機(jī)狀態(tài)節(jié)來(lái)聲明您處于在線狀態(tài)(參見(jiàn)? 清單 16 ):

清單 16. 建立一個(gè) XMPP 連接

$conn->connect();

$conn->processUntil('session_start');

$conn->presence();

下一步是發(fā)送消息本身,該消息已被預(yù)先填充到一個(gè)名為 $message 的變量中(參見(jiàn)? 清單 17 ):

清單 17. 發(fā)送消息

$conn->message($CONFIG['receive'], $message);

然后您使用 $conn->disconnect(); 斷開(kāi)連接。

在此過(guò)程中,您可能會(huì)遇到錯(cuò)誤。 清單 18 ?將清單? 15 、 16 ?和? 17 ?中的代碼放到一個(gè)將插入到 lib.inc.php 中的函數(shù)中。在這個(gè)過(guò)程中,它將發(fā)送一條消息的業(yè)務(wù)封裝到一個(gè) try/catch 語(yǔ)句中,該語(yǔ)句將把任何異常消息寫入錯(cuò)誤日志中。

清單 18. 完整的 send_notification 函數(shù),包含 try/catch 語(yǔ)句以記錄錯(cuò)誤

/**

* Updates everyone's user interface with a message

*/

function send_notification($message) {

// Load configuration

global $CONFIG;

$conn = new XMPPHP_XMPP(

$CONFIG['connect']->host,

5222,

$CONFIG['connect']->user,

$CONFIG['connect']->pass,

$CONFIG['connect']->resc);

try {

$conn->connect();

$conn->processUntil('session_start');

$conn->presence();

$conn->message($CONFIG['receive'], $message);

$conn->disconnect();

} catch(XMPPHP_Exception $e) {

error_log($e->getMessage());

}

}

您可以對(duì)任意數(shù)量的公共通知應(yīng)用程序使用這個(gè)簡(jiǎn)單的機(jī)制。這里,您向訪問(wèn)站點(diǎn)的所有用戶發(fā)送相同的通知,但通過(guò)以下機(jī)制來(lái)定制通知是件麻煩事:

每個(gè)用戶被賦予一個(gè)惟一會(huì)話字符串,或者一個(gè)特定于某個(gè)特殊興趣或搜索的共享字符串;

這個(gè)字符串作為資源片段被添加到接收方的 JID;

消息然后被發(fā)送到 user@domain/session-string JID。


獲取外部數(shù)據(jù)

接下來(lái),您需要一個(gè)函數(shù)(參見(jiàn)? 清單 19 )來(lái)從您的指定提要檢索最新的 RSS 條目:

清單 19. 獲取 RSS 提要中的最新條目

function get_last_feed_item() {

global $CONFIG; // Load configuration

$rss = new lastRSS; // Initialize lastRSS

$rss->CDATA = 'content';

if ($rs = $rss->get($CONFIG['rss'])) {

if (isset($rs['items'][0]))

return $rs['items'][0];

else

return false;

}

}

這個(gè)函數(shù)初始化 lastRSS,加載您配置的 RSS 提要(這里是 IBM developerWorks Web development 專區(qū)的最新文章提要),將最頂端的條目返回為一個(gè)數(shù)組。擁有這個(gè)最新提要條目后,您需要知道自從上次檢查以來(lái),該條目是否被更改。為此,您需要使用一個(gè)小型文本文件。為保護(hù)應(yīng)用程序,最好使用數(shù)據(jù)庫(kù)或另一種方法,但對(duì)于測(cè)試目的,可以放心使用一個(gè)小型文件緩存。這個(gè)緩存在您每次檢查時(shí)都存儲(chǔ)最新提要條目的 URL;如果這個(gè) URL 更改,那么您就有一個(gè)新條目,應(yīng)該通知用戶。另一個(gè)函數(shù) feed_has_changed 將據(jù)此返回 true 或 false。不管是哪種情況,它都會(huì)將這個(gè)最新 URL 保存到緩存文件中,為下次檢查做好準(zhǔn)備。 清單 20 ?展示了 feed_has_changed 函數(shù):

清單 20. 返回任何新提要數(shù)據(jù)

function feed_has_changed($url) {

global $CONFIG;

$changed = false;

// Check to see if the file exists, and if it does, if

// the URL has changed

if (!file_exists($CONFIG['cachedir'] . 'cache.txt')) {

$changed = true;

} else if (file_get_contents($CONFIG['cachedir'] . 'cache.txt') != $url) {

$changed = true;

}

// If the URL has indeed changed, update the version in the cache

// and return true

if ($changed) {

file_put_contents($CONFIG['cachedir'] . 'cache.txt', $url);

return true;

}

// Otherwise return false

return false;

}

您將把最新條目的一個(gè)簡(jiǎn)單的 HTML 編碼版本傳遞給客戶端。在更高級(jí)的應(yīng)用程序中,可以以 JavaScript Object Notation (JSON) 或 XML 編碼該條目,多包括一些元數(shù)據(jù),并允許客戶端 JavaScript 根據(jù)設(shè)備和瀏覽器適當(dāng)格式化它。但是,對(duì)于現(xiàn)在, 清單 21 ?中的版本就夠用了。

清單 21. 將一個(gè)提要條目封裝在簡(jiǎn)單的 HTML 中

function last_item_html($item) {

return <<< END

<div class="item">

<div class="item_title">

<h2><a href="{$item['link']}"

target="_blank">{$item['title']}</a></h2>

</div>

<div class="item_body">

{$item['description']}

</div>

</div>

END;

}

最后,在您的 /pingstream 目錄中創(chuàng)建一個(gè)名為 backend.php 的新 PHP 文件。使用? 清單 22 ?中的簡(jiǎn)單 PHP 腳本作為文件內(nèi)容。這個(gè)腳本負(fù)責(zé)檢索 RSS 提要并通過(guò) XMPP 將最新提要條目的 JSON 編碼版本發(fā)送到您的接收方。

清單 22. 通過(guò) XMPP 發(fā)送封裝的提要條目

<?php

require_once('lib.inc.php');

if ($lastitem = get_last_feed_item()) {

if (feed_has_changed($lastitem['link'])) {

send_notification(last_item_html($lastitem));

}

}

這就是將動(dòng)態(tài)通知發(fā)送給應(yīng)用程序的公共用戶所需的全部?jī)?nèi)容。理想情況下,您應(yīng)該將 backend.php 腳本作為一個(gè)定期時(shí)間任務(wù)運(yùn)行。但是,對(duì)于測(cè)試目的,您可以通過(guò)一個(gè) web 瀏覽器手動(dòng)執(zhí)行該腳本。

瀏覽器應(yīng)用程序:Strophe.js 和 jQuery

在本小節(jié)中,您將編寫一些 JavaScript 函數(shù),以便通過(guò) BOSH 上的 XMPP 接收消息,并構(gòu)建一個(gè) HTML 用戶界面來(lái)顯示接收到的通知。

創(chuàng)建用戶界面

現(xiàn)在您需要?jiǎng)?chuàng)建用戶界面來(lái)接收通知。Strophe.js 是用于通過(guò) BOSH 發(fā)送和接收 XMPP 數(shù)據(jù)的常用 JavaScript 庫(kù)。對(duì)于 Pingstream 中的目的,您只需接收數(shù)據(jù),盡管有一點(diǎn)是顯而易見(jiàn)的:雙向通信允許您快速構(gòu)建豐富的協(xié)作環(huán)境。

盡管有幾個(gè)版本,但 Strophe 的 JavaScript 版本作為一個(gè)基于瀏覽器的 XMPP 客戶端對(duì)您而言是最有用的。下載壓縮包(參見(jiàn)? 參考資料 )并將其解壓縮到 pingstream 的 strophejs 文件夾中。

jQuery JavaScript 框架極大地簡(jiǎn)化了事件處理和 DOM 操作。本文提供的 Strophe.js 示例廣泛使用該框架,這兩者簡(jiǎn)直是 “天生一對(duì)”。下載 jQuery(參見(jiàn)? 參考資料 ?中的鏈接)并將這個(gè)縮微版放到 pingstream 中的 jquery 文件夾中。

新建一個(gè) index.html 文件。在該文件中包含對(duì)剛才下載的 Strophe 和 jQuery 庫(kù)的引用,以及對(duì)稍后即將定義的 pingstream.js 庫(kù)的引用。在? body ?元素中,添加一個(gè) ID 為 notifications 的? div ?元素,如? 清單 23 ?所示:

清單 23.? 客戶端 HTML? 頁(yè)面

<!DOCTYPE html>

<html>

<head>

<title>Latest content</title>

<script type="text/javascript"

src="jquery/jquery-1.4.2.min.js"></script>

<script type="text/javascript"

src="strophejs/strophe.js"></script>

<script type="text/javascript"

src="pingstream.js"></script>

</head>

<body>

<h1>Latest content:</h1>

<div id="notifications"></div>

</body>

</html>

創(chuàng)建 JavaScript 文件 — pingstream.js — 您剛才在? 清單 23 ?中引用的。在 pingstream.js 的頂端,定義此前在 Apache 中配置的 BOSH 代理端點(diǎn),如? 清單 24 ?所示:

清單 24.? 設(shè)置 BOSH? 端點(diǎn)

var BOSH_SERVICE = '/xmpp-httpbind';

var connection = null;

當(dāng)頁(yè)面完全加載后,您想自動(dòng)連接到 XMPP 服務(wù)器。您可以使用 jQuery 的? $(document).ready ?調(diào)用實(shí)現(xiàn)這個(gè)目標(biāo);其中,您新建一個(gè)? strophe.js Strophe.Connection ?對(duì)象并用它連接到服務(wù)器,如? 清單 25 ?所示:

清單 25.? 建立一個(gè)通過(guò) BOSH? 的連接

$(document).ready(function () {

connection = new Strophe.Connection(BOSH_SERVICE);

connection.connect( "sendinguser@127.0.0.1",

"sendingpass",

onConnect);

});

更健壯的選項(xiàng)

對(duì)于本教程的目的,您正在使用此前定義的發(fā)送方。對(duì)于一個(gè)更健壯的應(yīng)用程序,更好的方法可能是為每個(gè)注冊(cè)應(yīng)用程序用戶創(chuàng)建一個(gè)新用戶,并將每個(gè)用戶訂閱到一個(gè) “發(fā)布-訂閱” 界面。或者,如果您將用戶名和密碼留空并將 XMPP 服務(wù)器配置為接受這種類型的連接,那么 Strophe.js 可以匿名登錄。在這些情況下,將針對(duì)每個(gè)匿名用戶動(dòng)態(tài)創(chuàng)建一個(gè) JID;這些 JID 必須受到管理。最后,您還可以擴(kuò)展 XMPP 聊天室。

在? 清單 25 ?中, Strophe.Connection.connect ?方法包含一個(gè)對(duì)? onConnect ?函數(shù)的引用,作為它的一個(gè)參數(shù)。 onConnect ?將在連接建立后立即啟動(dòng)。您可以利用這個(gè)機(jī)會(huì)來(lái)為入向消息添加一個(gè)通知處理程序;您在這里注冊(cè)了一個(gè)名為? notifyUser ?函數(shù)。隨后,您發(fā)送了一個(gè)簡(jiǎn)單的聯(lián)機(jī)狀態(tài)節(jié)。

要確保您可以連接并接收新消息,您還需向用戶發(fā)送一個(gè)友好通知。

將? 清單 26 ?中的代碼添加到您的 JavaScript 文件中的? $(document)ready ?調(diào)用上方:

清單 26.? 處理入向 XMPP? 消息

function onConnect(status)

{

$('#notifications').html('<p class="welcome">Hello!

Any new posts will appear below.</p>');

connection.addHandler(notifyUser, null, 'message', null, null, null);

connection.send($pres().tree());

}

最后,由于您注冊(cè)了通知處理程序,因此,只要 XMPP 客戶端接收到消息節(jié),Strophe.js 就會(huì)調(diào)用? notifyUser(msg) ?函數(shù)。 msg ?參數(shù)是 XML 節(jié)本身的一個(gè)表示,可以如? 清單 27 ?所示查詢:

清單 27.? 查詢? msg 參數(shù)

var elems = msg.getElementsByTagName('body');

var body = elems[0];

$('#notifications').append(Strophe.getText(body));

理想情況下,您希望對(duì)消息進(jìn)行限制,以便只顯示您的服務(wù)器端發(fā)送用戶發(fā)送的消息。您可以將它封裝到構(gòu)成? notifyUser ?函數(shù)主體的一個(gè)? if ?語(yǔ)句中,如? 清單 28 ?所示:

清單 28.? notifyUser 函數(shù)

function notifyUser(msg)

{

if (msg.getAttribute('from') == "testuser@127.0.0.1/pingstream") {

var elems = msg.getElementsByTagName('body');

var body = elems[0];

$('#notifications').append(Strophe.getText(body));

}

return true;

}

這個(gè)函數(shù)應(yīng)位于在? 清單 26 ?中定義的? onConnect ?函數(shù)上方。


最終效果

在一個(gè) web 瀏覽器中打開(kāi)您的 index.html 文件。您應(yīng)該會(huì)看到一個(gè)簡(jiǎn)單的標(biāo)題和一條消息,該消息稱更新將在下面顯示(這可能會(huì)使您回想起您發(fā)給自己的測(cè)試通知,稱 XMPP 連接正在成功運(yùn)行)。

現(xiàn)在加載 backend.php。就像變戲法一樣,來(lái)自 IBM developerWorks Web development 專區(qū)的最新更新將顯示在您的頁(yè)面上。其他帶有 RSS 提要的示例源包括 Twitter 帳戶、通訊社、以及來(lái)自服務(wù)器監(jiān)控軟甲的更新提要。

這是開(kāi)發(fā)一個(gè)強(qiáng)大平臺(tái)的簡(jiǎn)單起點(diǎn)。Strophe.js 能夠促進(jìn)應(yīng)用程序的雙向通信,盡管更簡(jiǎn)單的方法是使用標(biāo)準(zhǔn)的 jQuery HTTP 回?fù)軄?lái)將用戶輸入送入系統(tǒng),從而避免為您的應(yīng)用程序編寫一個(gè) XMPP 后臺(tái)監(jiān)控進(jìn)程的麻煩。更令人興奮的是,當(dāng)您 web 服務(wù)器用作 BOSH 代理時(shí),完全無(wú)需太多來(lái)自服務(wù)器端 web 應(yīng)用程序的輸入,兩個(gè)或更多 web 客戶端就能通過(guò) XMPP 相互通信。這種技術(shù)將對(duì)從辦公室協(xié)作軟件到游戲的很多軟件產(chǎn)生深遠(yuǎn)影響。

結(jié)束語(yǔ)

本教程討論了實(shí)時(shí) web 應(yīng)用程序的必要性,以及 XMPP 如何克服現(xiàn)有技術(shù)的缺點(diǎn)。為展示這種方法的效果,您使用 XMPPHP、Last RSS、Strophe.js、Openfire 和 PHP 開(kāi)發(fā)了一個(gè)簡(jiǎn)單的 RSS 更新通知應(yīng)用程序。

盡管需要一個(gè)附加服務(wù)器層和一些 JavaScript 新技術(shù),但 XMPP 比傳統(tǒng) Ajax 輪詢模型更加適合實(shí)時(shí) web 應(yīng)用程序。XMPP 更快,在開(kāi)發(fā)和系統(tǒng)基礎(chǔ)設(shè)置方面需要的開(kāi)銷更少,并且使用一個(gè)強(qiáng)大的新興 web 開(kāi)發(fā)標(biāo)準(zhǔn)。

下載

描述

名字

大小

下載方法

Pingstream 源代碼

pingstream.zip

238KB

HTTP

參考資料

學(xué)習(xí)

l 您可以參閱本文在 developerWorks 全球網(wǎng)站上的? 英文原文

l? XMPP Standards Foundation :訪問(wèn) XMPP 官方站點(diǎn)。

l? 實(shí)現(xiàn)可擴(kuò)展消息傳遞和到場(chǎng)協(xié)議(XMPP) (M. Tim Jones,developerWorks,2009 年 9 月):探索 XMPP 的細(xì)節(jié),了解如何將它用于簡(jiǎn)單消息傳遞。

l? 使用 XMPP、SMS、pureXML 和 PHP 創(chuàng)建警報(bào)系統(tǒng) (Joe Lennon,developerWorks,2009 年 11 月):嘗試使用 XMPP 來(lái)將通知發(fā)送到 Google Talk。

l? Jabber (Gerhard Poul,developerWorks,2002 年 5 月):查看這個(gè)早期 XMPP 簡(jiǎn)介。

l? Ajax 和 XML: 將 Ajax 用于聊天 (Jack D Herrington,developerWorks,2007 年 12 月):了解如何使用 Ajax 輪詢實(shí)現(xiàn)一個(gè)實(shí)時(shí) web 應(yīng)用程序。

l? JavaScript Tutorial :了解如何使用這個(gè) web 腳本語(yǔ)言。

l? Ejabberd :進(jìn)一步了解這個(gè)用 Erlang 語(yǔ)言編寫的 XMPP 服務(wù)器。

l? My developerWorks: 個(gè)性化您的 developerWorks 體驗(yàn)。

l? IBM XML 認(rèn)證 :了解如何才能成為一名 IBM 認(rèn)證的 XML 和相關(guān)技術(shù)的開(kāi)發(fā)人員。

l? XML 技術(shù)庫(kù) :訪問(wèn) developerWorks XML 專區(qū),獲得廣泛的技術(shù)文章和技巧、教程、標(biāo)準(zhǔn)和 IBM 紅皮書。

l developerWorks? 技術(shù)活動(dòng) ?和? 網(wǎng)絡(luò)廣播 :隨時(shí)關(guān)注這些活動(dòng)中的技術(shù)。

l? developerWorks 播客 :收聽(tīng)面向軟件開(kāi)發(fā)人員的有趣訪談和討論。

獲得產(chǎn)品和技術(shù)

l? Openfire :下載 Openfire,這是一個(gè)基于 XMPP (Jabber) 協(xié)議的跨平臺(tái)實(shí)時(shí)協(xié)作服務(wù)器。

l? PHP :訪問(wèn)這個(gè) PHP 站點(diǎn),獲取這個(gè)應(yīng)用廣泛的腳本語(yǔ)言,該語(yǔ)言非常適合 Web 開(kāi)發(fā),可以嵌入到 HTML 中。本教程使用 PHP 5.2 或更高版本。

l? Apache HTTP Server :下載這個(gè) Apache web 服務(wù)器。

l? MySQL :下載這個(gè)開(kāi)源事務(wù)型數(shù)據(jù)庫(kù)。

l? DB2 Express-C :下載這個(gè)免費(fèi)版 IBM DB2 數(shù)據(jù)庫(kù)服務(wù)器,它是中小型企業(yè)應(yīng)用程序開(kāi)發(fā)的一個(gè)堅(jiān)實(shí)基礎(chǔ)。

l? Openfire 插件 :獲取用于 Openfire 的 User Service 插件。

l? XMPPHP :從這個(gè)項(xiàng)目的 Google Code 站點(diǎn)下載 PHP XMPP Library。

l? Last RSS :獲取 Vojtech Semecky 針對(duì) PHP 的 RSS 解析器(經(jīng)過(guò) GNU Public License version 2 許可)。

l? jQuery :下載 jQuery JavaScript 庫(kù),經(jīng)過(guò) MIT 或 GNU Public License 許可。

l? Strophe :下載 Strophe.js,這是一系列用于編寫 XMPP 客戶端的庫(kù)。它的許可允許對(duì)其進(jìn)行自由使用、修改和共享。

l? phpMyAdmin :獲取這個(gè)免費(fèi)軟件工具,它支持通過(guò) web 管理 MySQL。

l? IBM 產(chǎn)品評(píng)估試用版軟件 :下載或? 在線試用 IBM SOA Sandbox ,并開(kāi)始使用來(lái)自 DB2?、Lotus?、Rational?、Tivoli? 和 WebSphere? 的應(yīng)用程序開(kāi)發(fā)工具和中間件產(chǎn)品。

討論

l? XMPP Discussion :訂閱面向開(kāi)發(fā)人員、系統(tǒng)管理員和用戶的 XMPP 討論。

l? XML 專區(qū)討論論壇 :參與任何一個(gè) XML 相關(guān)討論。

l? developerWorks 博客 :閱讀這些博客并參與討論。

?

引用: http://www.cnblogs.com/alex-blog/articles/2665665.html
?

?

補(bǔ)充:如果相關(guān)的環(huán)境都配置成功時(shí),使用xmpp.php庫(kù)進(jìn)行相關(guān)的消息發(fā)送如果出現(xiàn)如下的錯(cuò)誤,那么就是您的服務(wù)器上面的ssl沒(méi)有配置成功,具體的一個(gè)配置方法如下所示:

可能碰到的問(wèn)題
1、驗(yàn)證時(shí)提示錯(cuò)誤 :Warning: stream_socket_enable_crypto() [streams.crypto]: this stream does not support SSL/crypto in H:\13.PHP\04.WorkSpaces\XMPPHP\XMPP.php?
問(wèn)題原因:未安裝openssl擴(kuò)展
解決方案:安裝openssl擴(kuò)展
?解決方法:

意思是不支持ssl,輸出phpinfo,發(fā)現(xiàn)自己的php環(huán)境沒(méi)有安裝ssl擴(kuò)展,有些默認(rèn)安裝了,有些沒(méi)有安裝

這里寫下windows下的安裝方法
1、拷貝PHP 目錄中的libeay32.dll, ssleay32.dll, php5ts.dll, php ext 目錄下 php_curl.dll 文件到
system32 目錄。(一定要拷貝全啊,不要丟掉哪個(gè),不然會(huì)報(bào)錯(cuò)的)
2、修改php.ini:配置好extension_dir ,去掉extension = php_curl.dll? ?和 extension=php_openssl.dll 前面的分號(hào)。

3、重起apache。

再次輸出phpinfo,看到如下內(nèi)容就安裝成功了

?這晨需要注意一下的是,您需要確認(rèn)你所更改的php.ini是否是真正的配置文件,我上回就碰到了一個(gè)問(wèn)題。在php的目錄下面,確實(shí)是存在一個(gè)Php.ini的文件,我改完相磁的配置以后,完全沒(méi)有反應(yīng),依然報(bào)如上的錯(cuò)誤。后面我使用phpinfo輸出一看才明白,其輸出的結(jié)果php.ini指向的文件并不是這個(gè)實(shí)際文件,而是另外的一名字,而后,我在那個(gè)文件中進(jìn)行了相應(yīng)的修改。結(jié)果可以正常的運(yùn)行。在此提醒一下大家。

2、Jabber驗(yàn)證時(shí)提示:Auth fail
問(wèn)題原因:Jabber服務(wù)器、用戶名、密碼設(shè)置錯(cuò)誤或者程序自身的bug
解決方案:按照上面步驟3進(jìn)行Jabber相關(guān)配置或者按照步驟5修改部分代碼
3、步驟6運(yùn)行腳本時(shí)提示:Call to undefined function pcntl_fork()
問(wèn)題原因:PHP未以fastcgi的方式運(yùn)行,未能找到函數(shù)
解決方案:配置一個(gè)以fastcgi的方式運(yùn)行的PHP來(lái)單獨(dú)運(yùn)行這個(gè)daemon

?

Openfire配置過(guò)程,以及與php交互注意事項(xiàng)。


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦?。。?/p>

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 延吉市| 太仆寺旗| 化德县| 肇东市| 开平市| 宁阳县| 定陶县| 天气| 海宁市| 万源市| 青州市| 达日县| 隆子县| 昂仁县| 连州市| 明光市| 溧阳市| 霍城县| 新宾| 南雄市| 阿城市| 平乐县| 梁河县| 游戏| 潜山县| 张家界市| 保亭| 肇源县| 漳平市| 名山县| 商洛市| 女性| 唐河县| 福泉市| 塔城市| 青龙| 新宾| 蕉岭县| 肇庆市| 盘锦市| 静乐县|