• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴(yán)以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            關(guān)于Jabber客戶端

            來(lái)源:http://mcs.szu.edu.cn/user/shendasky/Article_16190

            Jabber客戶端

            現(xiàn)在網(wǎng)絡(luò)中最流行的程序,莫過(guò)于即時(shí)通訊軟件了,從ICQ到QQ,全世界約有7000萬(wàn)人每天在使用它們。人們利用它來(lái)溝通、交流,它是繼電子郵件之后另一個(gè)最成功的通訊工具。如此成功的軟件模式引出了一系列出色產(chǎn)品的誕生:ICQ,Yahoo! Messenger, AOL Instant Messenger,MSN Instant Messenger及中國(guó)人用的最多的QQ,而其中有一個(gè)較之其他通訊程序更璀璨奪目的明珠,那就是Jabber工程。

              Jabber是一個(gè)基于開放模式的軟件工程,現(xiàn)在的主要目的運(yùn)用于即時(shí)通訊(Instant Messaging System),Jabber并非第一個(gè)發(fā)明者,但它擁有幾個(gè)非同一般的特點(diǎn):
              
               *基于XML
              *分布式構(gòu)架
              *開放式協(xié)議與代碼庫(kù)
              *方便的、可擴(kuò)展的組件模式

              這些特點(diǎn)使得jabber一出世,便深受矚目,可以毫不避諱的說(shuō),幾大流行通訊軟件(如Yahoo!,AOL Messager,還有tencent 的 QQ)都是從jabber的代碼庫(kù)中發(fā)展而來(lái)的。而它基于XML的通訊協(xié)議,使得跨平臺(tái)很容易就能實(shí)現(xiàn),現(xiàn)在的jabber已經(jīng)可以使PC,Palm(掌上電腦類)以及SMS(短信息)、WAP互相溝通無(wú)礙了。總之,jabber的發(fā)展激動(dòng)人心,它極有可能成為未來(lái)的即時(shí)通訊標(biāo)準(zhǔn)。

              以下介紹的是Jabber的工作狀態(tài),依據(jù)版本為最新的1.4。


          1. Jabber前介
              
              Jabber Session
              整個(gè) Jabber的交流是基于一個(gè)會(huì)話(session)過(guò)程的,Jabber會(huì)話開始后,就會(huì)同指定服務(wù)器的端口5222(或者是5223,如果使用SSL 進(jìn)行加密的話)進(jìn)行TCP連接。WellJabber作為一個(gè)演示性程序,沒(méi)有將SSL選項(xiàng)包含在內(nèi)——需要注意的是,并非所有的服務(wù)器端都支持SSL。

              Jabber發(fā)送的數(shù)據(jù)流是由一個(gè)連續(xù)不斷的XML文檔構(gòu)成的,它的根元素為<stream>,而只有當(dāng)C/S兩端都注銷時(shí)——即發(fā)出 </stream>關(guān)閉標(biāo)記,這個(gè)XML文檔才算徹底結(jié)束。在<stream./>里的子元素們都是做為命令出現(xiàn)的,各自包括自己的屬性、內(nèi)嵌元素,以此作為參數(shù)。

              服務(wù)器/客戶端兩邊的連接都是異步傳輸模式,這不同于諸如POP這樣的協(xié)議,在你發(fā)出一個(gè)命令時(shí),不需要等待另一端的回應(yīng),可以直接發(fā)出下一個(gè)(命令)。此外,服務(wù)器可以隨時(shí)向你發(fā)出指示(比如說(shuō),當(dāng)你的一個(gè)好友上線或離線時(shí)),這就意味著你得隨時(shí)作好處理這些指示的準(zhǔn)備。

              那如何將一個(gè)回應(yīng)同特定的命令對(duì)應(yīng)起來(lái)呢?這是id屬性需要做的事。你發(fā)出一個(gè)命令時(shí),需要包含這個(gè)屬性 ——以一個(gè)恰當(dāng)?shù)奈ㄒ恢党霈F(xiàn),而從服務(wù)器返回的回應(yīng),也包括同樣的屬性值。具體處理時(shí),可以用一個(gè)散列表(Hash Table)作為id值,以此來(lái)標(biāo)識(shí)那些需要回應(yīng)的請(qǐng)求等數(shù)據(jù)。當(dāng)然,設(shè)置合適的id值是服務(wù)器端的事,客戶端所要做的是隨時(shí)接收server發(fā)來(lái)的指示,在編寫代碼時(shí),可以開辟一條單獨(dú)的線程或利用一個(gè)select/event來(lái)響應(yīng)接收的信息。這些在C/C++中都擁有良好的支持,但PHP則不行,因?yàn)樗吘故悄_本語(yǔ)言,不能進(jìn)行系統(tǒng)函數(shù)的調(diào)用,所以WellJabber暫時(shí)只能做到請(qǐng)求/回應(yīng)的模式,不能做到隨時(shí)處理主動(dòng)接收的信息,也就是當(dāng)好友發(fā)一個(gè)信息給你時(shí),你沒(méi)有辦法去判斷、接收它。因?yàn)檫@個(gè)至少需要一個(gè)循環(huán)來(lái)處理接收,但在腳本中出現(xiàn)這個(gè)循環(huán)意味著你的程序在信息到來(lái)之前始終不能完成,這是相當(dāng)可怕的。對(duì)  WellJabber來(lái)說(shuō),這的確是個(gè)不小的遺憾。

              Parsing XML
              實(shí)際處理時(shí),最困難的部分可能就是解析XML文檔了,但幸運(yùn)的是XML不同于HTML,它有著嚴(yán)格的語(yǔ)法定義和格式,比如所有標(biāo)記和屬性都是大小寫敏感的,所有的屬性結(jié)束時(shí)都要求明確的關(guān)閉標(biāo)記,屬性值、標(biāo)記外的文本內(nèi)容都不得與XML保留字相同(如<、 >、&、’、” 這樣一些,如果需要可以用& entity;的形式代替),還有就是非ASCII碼字符集的文檔要求在<?xml>中明確標(biāo)識(shí),通常中文可以處理為:

              <?xml version="1.0" encoding="GB2312" ?>
              或<?xml version="1.0" encoding="BIG5" ?>

              自己寫出一個(gè)XML解析程序是完全有可能的,但幸運(yùn)的是,有很多標(biāo)準(zhǔn)的XML解析程序(庫(kù))可供我們使用,比如使用PHP編寫的WellJabber 實(shí)際上就是利用expat作為解析模塊。這里要注意的一點(diǎn)是,你的解析程序必須能處理任何得到的XML數(shù)據(jù)片段,因?yàn)榍懊嬉呀?jīng)說(shuō)過(guò),jabber中傳遞的 XML數(shù)據(jù)并非完整的,一個(gè)徹底結(jié)束的數(shù)據(jù)流(以<stream/>結(jié)尾)要到程序注銷時(shí)才能出現(xiàn)。

              補(bǔ)充:Expat是一個(gè)很有名的XML解析程序,很多出色的軟件工程使用它做為XML文檔的解析模塊,譬如PHP及Perl等。

              Writing XML
              寫XML數(shù)據(jù)相對(duì)來(lái)說(shuō)比較簡(jiǎn)單了,但仍要注意必須寫得符合語(yǔ)法要求,少一個(gè)引號(hào)都可能引起服務(wù)器拒絕處理、甚至是斷開連接。


              
          2. 登錄/注銷Jabber會(huì)話

              Opening the session
              當(dāng)你打開位于5222(或5333)端口上的socket后,需要發(fā)送一個(gè)標(biāo)準(zhǔn)的XML頭,以此來(lái)打開一個(gè)以<stream>開始的完整jabber會(huì)話。

            <?xml version=”1.0” encoding =”UTF-8”?>
            <stream:stream
            to=”jabber.org”
            xmlns=”jabber:client”
            xmlns:stream=http://etherx.jabber.org/streams>

              這樣就可以喚醒服務(wù)器了,這時(shí)服務(wù)器會(huì)回應(yīng)大致如下信息:
            <?xml version=”1.0” encoding=”UTF-8”?>
            <stream:stream
            from=”jabber.org”
            id=”39ABA7D2”
            xmlns=”jabber:client”
            xmlns:stream=http://etherx.jabber.org/streams>

              這時(shí)XML解析器就可以發(fā)揮作用了,它提取并保留當(dāng)前的id值,因?yàn)楸敬蜫abber Session就依靠它來(lái)標(biāo)識(shí)了。

              我使用TCP Echo Client測(cè)試了一下,的確是如[JPO]中所述的一樣,只是要手工輸入XML代碼比較麻煩。
            Logging in
              
              這時(shí)服務(wù)器等待你的身份驗(yàn)證,你使用<iq>詢問(wèn)[JPO 1.5]來(lái)發(fā)送你的認(rèn)證信息,而服務(wù)器據(jù)此返回一個(gè)回應(yīng),指示你的登錄是否成功。[JPO 1.5.3.3]

              具體來(lái)說(shuō),詢問(wèn)使用jabber:iq:auth空間名稱和<username>以及<resource>元素來(lái)標(biāo)識(shí)用戶的jabber ID和計(jì)算機(jī)的resource名[JPO 1.6.3] 。

              在認(rèn)證過(guò)程中,使用明文傳遞密碼是不提倡的,比較安全的做法是配合使用一個(gè)包含已編碼digest的<digest>元素。這個(gè) digest是根據(jù)session ID和密碼組合成的字符串,結(jié)合SHA-1算法生成一個(gè)20個(gè)字節(jié)的散列,然后再將其轉(zhuǎn)變?yōu)椋矗皞€(gè)字節(jié)的16進(jìn)制形式。當(dāng)發(fā)出這個(gè)登錄詢問(wèn)后,就開始等待回應(yīng)了。接下來(lái)你會(huì)收到<iq type=”reply”>的數(shù)據(jù),至此,你已經(jīng)成功登錄了。假如回應(yīng)中type="error",則表示登錄失敗,這時(shí)得立即關(guān)閉session了。

              Logging Out

              當(dāng)要注銷退出時(shí),只需簡(jiǎn)單的發(fā)出”</stream:stream>”數(shù)據(jù)即可,這樣就通知服務(wù)器,本次XML數(shù)據(jù)流結(jié)束,然后關(guān)閉 socket。有時(shí)候,socket會(huì)出乎意料的關(guān)閉,比如說(shuō)當(dāng)Jabber服務(wù)器進(jìn)程中斷時(shí)。比較嚴(yán)重的問(wèn)題是,一般TCP Socket不能分辨清楚一個(gè)空閑連接和一個(gè)斷開的連接(可能發(fā)生在計(jì)算機(jī)崩潰或網(wǎng)絡(luò)斷開時(shí)),這時(shí)不會(huì)收到任何數(shù)據(jù),這對(duì)一個(gè)向jabber一樣的實(shí)時(shí)通訊協(xié)議來(lái)說(shuō),是個(gè)棘手的問(wèn)題:你可以想象一下,此時(shí)你仍然在線,而你的好友列表還是有效,但除非你試圖發(fā)送一個(gè)訊息,否則你不會(huì)知道你已經(jīng)斷開連接了。更為嚴(yán)重的是,一些防火墻和路由器在發(fā)現(xiàn)你長(zhǎng)時(shí)間沒(méi)有動(dòng)作后,會(huì)做自動(dòng)斷開連接。

              有兩種方法來(lái)解決這個(gè)問(wèn)題,一種比較簡(jiǎn)單,就是每隔一分鐘左右的時(shí)間就發(fā)送一個(gè)bit的XML數(shù)據(jù),假如你的計(jì)算機(jī)沒(méi)有得到服務(wù)器的回應(yīng),操作系統(tǒng)就將檢查連接是否斷開,并指出一個(gè)錯(cuò)誤。還有一種復(fù)雜的方法就是設(shè)置你操作系統(tǒng)的網(wǎng)絡(luò)API中套接字的”keep-alive”選項(xiàng),只需將超時(shí)間隔調(diào)整到幾分鐘即可,這個(gè)方法是否可行,依賴于你的操作系統(tǒng)(在win32平臺(tái)上,可以用 setsockopt函數(shù)配合SO_KEEPALIVE或SO_KEEPALIVE_VALS來(lái)修改這個(gè)選項(xiàng))。

            • 用戶在線狀態(tài)
                
                即時(shí)通訊客戶端程序中要處理的一個(gè)重要模塊就是,通知服務(wù)器用戶的在線狀態(tài)。當(dāng)你登錄后或改變?cè)诰€狀態(tài)時(shí),都需要通知服務(wù)器。(比如QQ中經(jīng)常使用的“我在吃飯,請(qǐng)過(guò)一會(huì)兒再和我聯(lián)系”,“我正在工作中”等等,這些都屬于用戶的在線狀態(tài))

                要報(bào)告一個(gè)狀態(tài)信息的改變,只需要發(fā)送一個(gè)<presence>元素[JPO 1.4]。它的類型屬性不是available就是 unavailable。你不需要添加"from"或"to"屬性,服務(wù)器在將你的狀態(tài)信息發(fā)給你的好友時(shí),會(huì)自動(dòng)添加它們。[JPO 1.4.1.1, 1.4.1.5]unavailable狀態(tài)可以很方便的使用戶處于“隱身”:在你的好友看起來(lái),你就象根本沒(méi)有在線。

                接受你好友的在線信息正好相反:你會(huì)收到他們發(fā)送的<presence>數(shù)據(jù)。當(dāng)你登錄后,你會(huì)收到每位好友這樣的數(shù)據(jù),以更新你好友列表的內(nèi)容。這個(gè)元素可能包括一個(gè)使用jabber:x:delay命名空間的<x>標(biāo)記,來(lái)通知你好友狀態(tài)信息最后改變的時(shí)間。[JPO 1.6.18,  JPG p.89]只要你在線,這些狀態(tài)信息隨時(shí)都會(huì)發(fā)送給你。


                
            • 管理好友列表
                
                好友資料(Roster)的管理是一個(gè)比較頭疼的事情,至少?gòu)默F(xiàn)在協(xié)議的描述來(lái)看。

                How the roster works

                好友資料的處理工作包括:用戶的狀態(tài),好友的狀態(tài)以及那些想加好友但尚未驗(yàn)證通過(guò)的請(qǐng)求。Jabber服務(wù)器存儲(chǔ)用戶的好友資料,并負(fù)責(zé)在如下情況下通知已登錄的用戶其好友資料的改變:用戶添加或刪除一個(gè)好友,其他用戶在好友列表中添加或刪除你,用戶通過(guò)或拒絕加入好友的驗(yàn)證。這些都籠統(tǒng)的稱作好友資料更新。這些更新通知都是作為<iq>元素(使用jabber:iq:roster命名空間)數(shù)據(jù)來(lái)發(fā)送的。當(dāng)然,客戶端也可以主動(dòng)請(qǐng)求好友資料的更新:這個(gè)在登錄后通常都應(yīng)該進(jìn)行一次,以更新本地客戶端的好友資料。

                Subscribing & unsubscribing buddies

                添加或刪除好友是通過(guò)<presence>元素來(lái)進(jìn)行的,它的type屬性是subscribe或unsubscribe。接收或拒絕都是通過(guò)<presence>元素來(lái)進(jìn)行的(請(qǐng)求和應(yīng)答都有同樣的ID號(hào))總之,當(dāng)你的好友資料改變時(shí),服務(wù)器就會(huì)主動(dòng)通知你情況的改變。前面已經(jīng)說(shuō)過(guò),PHP編寫的WellJabber有很多限制,其中一條就是除非你主動(dòng)要求更新好友資料,否則很難及時(shí)反映好友在線情況。

                Manually updating the roster
                
                如果你想更新服務(wù)器端的好友資料,可以發(fā)送<iq type=”set”>元素,你這樣做并不是添加或刪除好友,而是更新與好友相關(guān)的資料,比如他們的昵稱或所屬組名。[JPO 1.6.12]

                More roster info

                完整的好友信息可以在通過(guò)一個(gè)<iq>詢問(wèn)接受vCard資料時(shí)獲得,前提是如果他們存儲(chǔ)了這樣的信息[JPO 1.6.26]。(關(guān)于vCard,實(shí)在又是一個(gè)很大的論題,所以作為演示例子的WellJabber沒(méi)有包含它)
          3. 用戶在線狀態(tài)
              
              即時(shí)通訊客戶端程序中要處理的一個(gè)重要模塊就是,通知服務(wù)器用戶的在線狀態(tài)。當(dāng)你登錄后或改變?cè)诰€狀態(tài)時(shí),都需要通知服務(wù)器。(比如QQ中經(jīng)常使用的“我在吃飯,請(qǐng)過(guò)一會(huì)兒再和我聯(lián)系”,“我正在工作中”等等,這些都屬于用戶的在線狀態(tài))

              要報(bào)告一個(gè)狀態(tài)信息的改變,只需要發(fā)送一個(gè)<presence>元素[JPO 1.4]。它的類型屬性不是available就是 unavailable。你不需要添加"from"或"to"屬性,服務(wù)器在將你的狀態(tài)信息發(fā)給你的好友時(shí),會(huì)自動(dòng)添加它們。[JPO 1.4.1.1, 1.4.1.5]unavailable狀態(tài)可以很方便的使用戶處于“隱身”:在你的好友看起來(lái),你就象根本沒(méi)有在線。

              接受你好友的在線信息正好相反:你會(huì)收到他們發(fā)送的<presence>數(shù)據(jù)。當(dāng)你登錄后,你會(huì)收到每位好友這樣的數(shù)據(jù),以更新你好友列表的內(nèi)容。這個(gè)元素可能包括一個(gè)使用jabber:x:delay命名空間的<x>標(biāo)記,來(lái)通知你好友狀態(tài)信息最后改變的時(shí)間。[JPO 1.6.18,  JPG p.89]只要你在線,這些狀態(tài)信息隨時(shí)都會(huì)發(fā)送給你。


              
          4. 管理好友列表
              
              好友資料(Roster)的管理是一個(gè)比較頭疼的事情,至少?gòu)默F(xiàn)在協(xié)議的描述來(lái)看。

              How the roster works

              好友資料的處理工作包括:用戶的狀態(tài),好友的狀態(tài)以及那些想加好友但尚未驗(yàn)證通過(guò)的請(qǐng)求。Jabber服務(wù)器存儲(chǔ)用戶的好友資料,并負(fù)責(zé)在如下情況下通知已登錄的用戶其好友資料的改變:用戶添加或刪除一個(gè)好友,其他用戶在好友列表中添加或刪除你,用戶通過(guò)或拒絕加入好友的驗(yàn)證。這些都籠統(tǒng)的稱作好友資料更新。這些更新通知都是作為<iq>元素(使用jabber:iq:roster命名空間)數(shù)據(jù)來(lái)發(fā)送的。當(dāng)然,客戶端也可以主動(dòng)請(qǐng)求好友資料的更新:這個(gè)在登錄后通常都應(yīng)該進(jìn)行一次,以更新本地客戶端的好友資料。

              Subscribing & unsubscribing buddies

              添加或刪除好友是通過(guò)<presence>元素來(lái)進(jìn)行的,它的type屬性是subscribe或unsubscribe。接收或拒絕都是通過(guò)<presence>元素來(lái)進(jìn)行的(請(qǐng)求和應(yīng)答都有同樣的ID號(hào))總之,當(dāng)你的好友資料改變時(shí),服務(wù)器就會(huì)主動(dòng)通知你情況的改變。前面已經(jīng)說(shuō)過(guò),PHP編寫的WellJabber有很多限制,其中一條就是除非你主動(dòng)要求更新好友資料,否則很難及時(shí)反映好友在線情況。

              Manually updating the roster
              
              如果你想更新服務(wù)器端的好友資料,可以發(fā)送<iq type=”set”>元素,你這樣做并不是添加或刪除好友,而是更新與好友相關(guān)的資料,比如他們的昵稱或所屬組名。[JPO 1.6.12]

              More roster info

              完整的好友信息可以在通過(guò)一個(gè)<iq>詢問(wèn)接受vCard資料時(shí)獲得,前提是如果他們存儲(chǔ)了這樣的信息[JPO 1.6.26]。(關(guān)于vCard,實(shí)在又是一個(gè)很大的論題,所以作為演示例子的WellJabber沒(méi)有包含它)

          5. 發(fā)送信息時(shí),使用一個(gè)<message>元素[JPO 1.3],它使用”to”屬性來(lái)標(biāo)識(shí)接收者;反之,你接受包含”from”屬性的<message>元素,它標(biāo)識(shí)了發(fā)送者。

              實(shí)際上,任何人都可以發(fā)送信息給別人,你不需要特定的權(quán)限就可以查看到別人的在線狀態(tài)。這會(huì)造成信息的騷擾與泛濫嗎?要解決這個(gè)情況,就要使程序有對(duì)信息進(jìn)行篩選的能力,只允許從好友處來(lái)的信息,其他一律過(guò)濾掉。

              Message attributes
              我們收到的任何信息都包括一個(gè)<form>屬性,它給出了信息的發(fā)送者。同電子郵件相比,它的認(rèn)證更為可靠,因?yàn)檫@個(gè)屬性是由jabber服務(wù)器端來(lái)添加的,這就減少了發(fā)送者進(jìn)行欺詐行為的可能性。

              一個(gè)信息還應(yīng)該包括一個(gè)<subject>元素,它標(biāo)識(shí)了本次信息的主題,但顯示與否取決于接收者所使用的客戶端程序。

              一個(gè)信息還可以包括一個(gè)時(shí)間戳,這是用一個(gè)<x>元素來(lái)實(shí)現(xiàn)的,它使用了jabber:x:delay命名空間。

              而使用jabber:x:envelope命名空間還可以提供群發(fā)的功能,這就象傳統(tǒng)的電子郵件一樣。[JPO 1.6.20]

              The message body
              一個(gè)信息總是用<body>元素來(lái)包含其具體內(nèi)容的。[JPO 1.3.3.1]
            當(dāng)然也可以包含可選的元素<html>,它將提供HTML格式的信息。[JPO 1.3.3.3]但是需要注意的是,這個(gè)格式是基于XHTML的(w3.org制定的一種由HTML向XML過(guò)渡的格式)。

              對(duì)于HTML的使用者來(lái)說(shuō),會(huì)發(fā)現(xiàn)XHTML與其有很大的不同,因?yàn)樵O(shè)計(jì)XHTML時(shí)就考慮了客戶端類型的限制(譬如說(shuō)手機(jī)),具體體現(xiàn)為缺少一些常用的HTML元素,如<b>,<i>及<font>,但它們?cè)赬HTML中都有等價(jià)替代元素,如< strong>代替了舊的<b>,但一般指定色彩或格式時(shí),都使用CSS(Cascading Style Sheet)。

              Jabber支持加密的信息傳送,它使用包含jabber:x:encrypted命名空間的<x>元素來(lái)處理。[JPO 1.6.19]文檔中對(duì)這段描述并不是很清楚,因此WellJabber并沒(méi)有對(duì)加密提供支持。

              Other types of content
              與MIME不同,jabber信息并沒(méi)有一個(gè)標(biāo)準(zhǔn)的格式來(lái)容納圖片或聲音,這就意味著你無(wú)法在信息中包含一幅圖片的數(shù)據(jù),除非是使用超鏈接的形式來(lái)指示它。

              你可以隨信息一起發(fā)送文件,但是文件的數(shù)據(jù)不能包含在<message>中,而是采用超鏈接的方式指明可以下載的文件。

              Message types and threads
              發(fā)送的信息可以使用”type”屬性來(lái)提示其顯示方式,如果沒(méi)有指明這個(gè)屬性,信息將獨(dú)立地顯示在單獨(dú)的窗口中。若”type=chat”則指明應(yīng)使用 one-to-one(類似QQ的兩人世界)聊天界面來(lái)顯示。此外還有”type=groupchat”,詳細(xì)參見(jiàn)[JPO 1.3.1.1—— 1.3.1.4]。
              
              最后有可能出現(xiàn)”type=error”這樣的屬性值,它表明在發(fā)送一個(gè)信息時(shí)出錯(cuò)了(比較常見(jiàn)的是,發(fā)送信息給一個(gè)不存在的jabber地址)。這時(shí)的回應(yīng)包含在一個(gè)<error>元素中。[JPO 1.3.1.3]

              為幫助客戶端顯示信息在相應(yīng)界面中,信息還可以包含一個(gè)<thread>元素,它包含一個(gè)指向信息流的唯一值,客戶端發(fā)送的第一個(gè)信息就應(yīng)該包括一個(gè)唯一的線程ID,而后繼的信息都應(yīng)該發(fā)送到此線程ID標(biāo)識(shí)的同一個(gè)線程中。(JPO建議thread ID由發(fā)送者的jabber ID及當(dāng)前時(shí)間以散列算法合成)

              Message event
              信息的發(fā)送者可以使用jabber:x:events命名空間來(lái)接受這樣的通告,即信息的接收者是否已經(jīng)查閱過(guò)本信息,或者他/她是否在進(jìn)行回復(fù)。這是個(gè)全新的功能,在演示程序WellJabber中沒(méi)有體現(xiàn)。

              Message expiration
              信息的發(fā)送者可以使用jabber:x:expire命名空間來(lái)確定信息的發(fā)送時(shí)效。[JPO 1.6.22]如果信息是離線存儲(chǔ)的,當(dāng)時(shí)效過(guò)去時(shí),即使對(duì)方用戶登錄,該信息也不會(huì)發(fā)給他/她。

            聊  天
              
              Jabber的群組聊天或會(huì)議機(jī)制允許多人同時(shí)進(jìn)行交流。

              這種多人交流的方式在客戶端實(shí)現(xiàn)時(shí)是比較復(fù)雜的,這是大家所公認(rèn)的,因?yàn)橛袃商琢奶靺f(xié)議在使用。群組聊天是最早采用的,而會(huì)議機(jī)制是新的,也更靈活(注意,現(xiàn)在只有jabber 1.4服務(wù)器版本才支持它——做為一個(gè)外接模塊)。實(shí)際上,協(xié)議本身仍在不段變化,還沒(méi)有最終形成標(biāo)準(zhǔn)。

              Creating a chat room
              在產(chǎn)生一個(gè)聊天室前,你需要有一個(gè)聊天室名和一個(gè)會(huì)議服務(wù)。服務(wù)可以由用戶來(lái)制定,或者通過(guò)發(fā)送jabber:iq:browse請(qǐng)求來(lái)檢索。聊天室名稱可以自己輸入,或者編程產(chǎn)生(比如,產(chǎn)生一個(gè)隨機(jī)的數(shù)字作為名稱)。

              為確認(rèn)聊天室名稱是否已被使用,可以發(fā)送<iq type=”get”>(含xmlns=”jabber:iq:browse”的命名空間)到聊天室,如果它不存在,你會(huì)收到error 404(沒(méi)有找到)錯(cuò)誤,反之,如果其已存在,你就得重新為聊天室取個(gè)名稱。QQ中體現(xiàn)在自建聊天室這個(gè)版塊。

              對(duì)于如何生成一個(gè)聊天室,有著不同的異議。編程者的實(shí)踐經(jīng)驗(yàn)是先發(fā)送presence到聊天室,如果已存在就加入它,沒(méi)有則發(fā)送set請(qǐng)求來(lái)建立它(發(fā)送包含xmlns=”jabber:iq:browse”的<iq type=”set”>命令)

              Joining a chat room
              需要加入一個(gè)聊天室時(shí)(它的ID已經(jīng)由用戶指定或在接到聊天邀請(qǐng)時(shí)確定),首先發(fā)送一個(gè)<presence>元素。注意不要添加 resource名在發(fā)送中,這是老的groupchat的做法,現(xiàn)在的conference已經(jīng)不采用了。如果你需要向下兼容性,可以發(fā)送 resource name。

              接下來(lái),發(fā)送包含xmlns=”jabber:iq:browse”的<iq type=”set”>,這個(gè)請(qǐng)求包含了一個(gè)或多個(gè)<nick>元素,它指明了你希望加入的會(huì)議的別名。一旦你接到一個(gè)成功回應(yīng),也就意味著你已經(jīng)加入這個(gè)聊天室。

              The chat’s roster
              每個(gè)聊天室都有個(gè)人員列表,表明當(dāng)前在聊天室中的人員。它會(huì)隨著人員加入或離開而改變。

              通知客戶端聊天室人員的方法有很多種。首先,發(fā)給每個(gè)成員<presence>元素,在你加入這個(gè)聊天室或有其他成員改變?cè)诰€狀態(tài)時(shí)(更新?tīng)顟B(tài)、信息或是離開)。

              此外,當(dāng)成員列表改變時(shí),自己會(huì)收到一個(gè)含有jabber:iq:conference命名空間的<iq>元素,它具體包括代理服務(wù)器上的 jabber ID以及當(dāng)前成員的昵稱。描述conference本身的是包含多個(gè)屬性的<conference>元素,如果包含< user>子元素,則標(biāo)識(shí)了當(dāng)前的成員們,這時(shí)通常帶有”jid” 屬性和”name”屬性。

              又如,當(dāng)一個(gè)成員加入、離開或是改變其昵稱時(shí),你就會(huì)收到一個(gè)類似的請(qǐng)求,它包含一個(gè)單獨(dú)的<user>元素。
              
              最后,服務(wù)器會(huì)發(fā)送一個(gè)類似“某某加入了”或“某某離開了”樣式的消息。
            隨便說(shuō)一下,如果你希望在聊天室查找某人,可以使用包含jabber:iq:borowse命名空間的<iq>元素來(lái)發(fā)送他/她的proxy JID。

              Chat invitations

              聊天邀請(qǐng)使用包含<xmlns=”jabber:x:conference”>的請(qǐng)求來(lái)實(shí)現(xiàn)。

              Sending and receiving messages

              要發(fā)送一個(gè)信息到聊天室,可以發(fā)送”type”為”groupchat”的<message>元素到聊天室地址。發(fā)送一個(gè)私人信息,可以到他們的proxy ID。

              收到的聊天信息依靠”groupchat”類型來(lái)辨識(shí),可以從”from”地址去處掉resource ID,此時(shí)剩下來(lái)的就是聊天室ID了。

              Jabber還支持IRC的“表情”聊天方式,這使聊天者能做出類似舞臺(tái)動(dòng)作的行為。(這個(gè)在QQ中是很常見(jiàn),也很有趣的)客戶端通過(guò)前綴”/me”來(lái)辨識(shí)這樣的信息,通常在顯示前應(yīng)該插入使用對(duì)象的昵稱。

              比如,可以發(fā)送這樣的信息”/me 笑瞇瞇的望著大家”,則客戶端就顯示為:
              Huwell 笑瞇瞇的望著大家

              Leaving the conference

              要離開聊天室時(shí),你只需要簡(jiǎn)單的發(fā)送一個(gè)<presence type=”unavailable”>元素即可。

              File Transfer

              Jabber不直接支持文件的傳送,而是依靠“帶外數(shù)據(jù)”(out-of-band)即OOB機(jī)制通過(guò)URL來(lái)超鏈接文件。這種解決方案使得發(fā)送者的客戶端要么上傳文件到一個(gè)特定的FTP/HTTP/WebDAV服務(wù)器,要么打開另一個(gè)端口,運(yùn)行一個(gè)常規(guī)服務(wù)在上面。這兩種方法下URL都會(huì)發(fā)送給接受者,他們便使用這個(gè)超鏈接來(lái)下載文件。注意,后一種機(jī)制在發(fā)送者隱藏在防火墻或NAT Server后時(shí)會(huì)失效,接收者不受影響。這種P2P的文件傳送功能非常有用。

              OOB不是僅為文件轉(zhuǎn)送來(lái)設(shè)計(jì)的,它可用來(lái)傳送任何URL,比如一個(gè)到心愛(ài)站點(diǎn)的鏈接,盡管一個(gè)HTML消息也可以支持它。

              有兩種相似的方法來(lái)傳送URL,一個(gè)就是將<x>嵌套在<message>元素中,并使用jabber:x:oob命名空間 [JPG p.92,JPO 1.6.23];第二種方法就是使用jabber:x:oob命名空間的<iq>元素請(qǐng)求[JPG p.53, JPO 1.6.9]后一種方法允許通過(guò)iq回應(yīng)來(lái)確認(rèn)。


              [*}注冊(cè)新用戶

              Jabber協(xié)議允許客戶端登記一個(gè)新的用戶,而不用通過(guò)web界面來(lái)或系統(tǒng)管理員來(lái)申請(qǐng)(當(dāng)然,任何服務(wù)器都允許這樣做)。登記新的帳戶有多種方法。

              登記時(shí),首先連接到服務(wù)器并打開一個(gè)<stream>元素,這就好象是正常登錄。只是發(fā)送的是使用jabber:iq:register命名空間的<iq type=”get”>元素。[JPG p57-62]
            如果服務(wù)器不允許登記新用戶的話,會(huì)回應(yīng)一個(gè)錯(cuò)誤。

              下列資料可以做為編程者設(shè)計(jì)登記新用戶界面的參考:
              <key>,這是一個(gè)需要隨著登記命令發(fā)送回服務(wù)器的認(rèn)證字符串。
              <instructions>,包含一個(gè)呈現(xiàn)給用戶的介紹。
              <username><nick><password><name><first><last><email>
              <addtress><city><state><zip><phone><url> <date><misc><text>,這些都是用戶的資料。屬于jabber Server1.4所需要的,如果開發(fā)出自己服務(wù)器版本,就可以自己定義這些用戶資料選項(xiàng)了。

              當(dāng)用戶一切就緒后,就可以發(fā)送包含上述資料的<iq type=”set”>回應(yīng)了,然后等待服務(wù)器的響應(yīng)。
              
              如果注冊(cè)新用戶成功,你會(huì)收到一個(gè)包含空的請(qǐng)求的回應(yīng)。你需要關(guān)閉連接,這個(gè)連接不能再做為登錄的連接重復(fù)使用了,你得另外打開一條新的。

              如果注冊(cè)失敗了,你將得到錯(cuò)誤的回應(yīng),如果錯(cuò)誤代碼是409(沖突),這意味著你注冊(cè)的用戶名是無(wú)效的。

              Updating registration

              如果要更新注冊(cè)信息(如密碼或電子郵件)可以通過(guò)發(fā)送<iq type=”set”>元素來(lái)完成。

              Canceling an account

              如果你需要終止一個(gè)帳號(hào),你先得通過(guò)發(fā)送一個(gè)<iq type=”get”>元素來(lái)獲得服務(wù)器的<key>,然后再發(fā)送包含<remove>子元素的<iq type=”set”>來(lái)達(dá)成。


              [*}WellJabber功能模塊

              開發(fā)一個(gè)jabber的客戶端不是一件簡(jiǎn)單的事,事實(shí)上標(biāo)準(zhǔn)的客戶端應(yīng)該包括:P2P聊天,聊天室,好友列表管理,資源管理,相關(guān)資料修改,信息加密處理,MSN網(wǎng)關(guān)(或者還包括Yahoo!,AOL等的信息轉(zhuǎn)換),在線搜索,認(rèn)證控制,離線信息轉(zhuǎn)發(fā),文件互傳等。

              一個(gè)比較成功的jabber客戶端是由jabber.com提供的JIM,此外還有很多優(yōu)秀的jabber客戶端,由于jabber的通訊協(xié)議是建立在 XML基礎(chǔ)上,而且是開放式的,所以任何語(yǔ)言都可以用來(lái)編寫客戶端,最常見(jiàn)的是Delphi,Java,C/C++,Perl,此外還有PHP, Python,JavaScript,甚至是Flash ActionScript都可以拿來(lái)編寫這樣的客戶端,我覺(jué)得一個(gè)開放式的應(yīng)用模式才是成功的,才會(huì)有長(zhǎng)足的進(jìn)步,這就象電子郵件,我們很難想象如果電子郵件的格式被一家所壟斷,只能使用一家所編寫的郵件程序去接收,那它還會(huì)這么普及、全球通用嗎?在這方面國(guó)內(nèi)的騰訊公司做的就很不好,顯然易見(jiàn),QQ的代碼也是從jabber中剝離出來(lái)的,但是QQ卻不肯公開它的通訊協(xié)議,一心只想做國(guó)內(nèi)即時(shí)通信的老大,這會(huì)造成兩個(gè)后果:一個(gè)是處在競(jìng)爭(zhēng)壓力小的情況下,它會(huì)停止不前,沒(méi)有進(jìn)步。

              我們看到,現(xiàn)在的QQ客戶端同以前的沒(méi)有什么太大的區(qū)別,不過(guò)界面更花哨些而已,沒(méi)有利益的驅(qū)動(dòng),騰訊現(xiàn)在連Linux,Palm等平臺(tái)都沒(méi)有推出,實(shí)際上很可悲。另一個(gè)是它只能在國(guó)內(nèi)發(fā)展,走不出國(guó)門,一旦即時(shí)通訊的國(guó)際標(biāo)準(zhǔn)制定,那它再這么固步自封,就會(huì)成為不合格的產(chǎn)品,下場(chǎng)也好不到哪去。所以希望騰訊公司能趕快覺(jué)醒,不要壟斷這個(gè)現(xiàn)在看起來(lái)很壯大的行業(yè)。QQ雖然很火,但比起Flash,Netscape又如何?這些世界聞名的軟件都是公開格式,甚至是代碼的,騰訊還不該向這些軟件學(xué)習(xí)嗎?當(dāng)年的Netsacape幾乎是獨(dú)步天下,可還是被IE后來(lái)居上了,現(xiàn)在微軟又在XP中捆綁了MSN,騰訊再不當(dāng)心,可真要尷尬了。

               WellJabber是使用PHP寫的,是典型的B/S結(jié)構(gòu)程序,之所以這樣考慮,是想使WellJabber具有跨平臺(tái)的特性,能夠在win32, Linux,Unix,Mac等系統(tǒng)上都順暢的運(yùn)行,因?yàn)樗抢脼g覽器做為承載平臺(tái)的。而且PHP發(fā)展到今天(最新的版本是Version 4)已經(jīng)很強(qiáng)大了,它具有多種函數(shù)庫(kù),如同C語(yǔ)言一樣,甚至融合的比C更體貼,就Jabber來(lái)看,PHP擁有必不可少的XML解析函數(shù),還有網(wǎng)絡(luò)連接函數(shù),以及加密函數(shù)(Hash散列,Base_64等),總之使用PHP來(lái)寫jabber的演示程序的確很方便,但PHP也不是十全十美的,畢竟,通過(guò)HTTP端口,很多有用的功能都實(shí)現(xiàn)不了,而且調(diào)用的不是系統(tǒng)級(jí)的函數(shù)(如connect),效率有所下降。

              本程序只預(yù)計(jì)包含五個(gè)功能模塊:用戶注冊(cè),用戶登錄,獲取好友列表,發(fā)送信息,用戶注銷。
            考慮到面向?qū)ο蟮奶匦裕琖ellJabber程序采用了類的定義,以方便腳本調(diào)用,支持類是PHP中很有用的特點(diǎn),特別是數(shù)據(jù)庫(kù)操作,如果能把一般SQL行為用類來(lái)封裝,那么在修改數(shù)據(jù)庫(kù)類型時(shí)將會(huì)很方便,做到以做少的改動(dòng)支持最大的兼容性。

              WellJabber中的類定義放在jabber.inc中,一共有6個(gè)行為,分別是:
              jabber->connect (server[, port])
              jabber->Login (username, password, resource,server[, port]) 
              jabber->messages (recipient, subject, body, type)
              jabber->register(username, password, email, resource, server[, port])
              jabber->GetRoster()
              jabber->_display_error_message()
               
              在定義好這幾個(gè)類以后,腳本就可以很方便的實(shí)現(xiàn)jabber的通訊功能,而不必重復(fù)代碼。配合模版的設(shè)計(jì),使得PHP版的Jabber更為方便靈活。
              
              根據(jù)jabber文檔中的描述,WellJabber類中定義了以下的成員變量,其值與特定含義分別是:
              
              name——用戶的真實(shí)姓名;
              email——用戶的電子郵件;
              password——用戶選用的密碼;
              username——用戶登錄名稱;
              resource——用戶的Location辨識(shí)名;
              sid——本次session的唯一標(biāo)識(shí)
              server——登錄服務(wù)器名稱;
              port——登錄服務(wù)器端口名稱;
              error_code——發(fā)送錯(cuò)誤的代碼;
              error——發(fā)送的錯(cuò)誤(描述)
              connect——本次連接的文件指針
              roster——好友資料數(shù)組

              首先,看一看內(nèi)部的出錯(cuò)處理函數(shù):_display_error_message():
               
              這里error的錯(cuò)誤描述實(shí)際上就是[JPO]的附錄所指明的錯(cuò)誤描述代碼,這是標(biāo)準(zhǔn)的,由服務(wù)器發(fā)回的。
              
              Jabber類中要處理的錯(cuò)誤列表為:
              
              Bad Request

              這個(gè)表明jabber客戶端發(fā)送的數(shù)據(jù)不能為server端理解,通
            常是由于數(shù)據(jù)流不符合jabber協(xié)議而引起的。(譬如,jabber客戶端發(fā)送了一個(gè)subscriptioj給自己,或者是發(fā)送了一個(gè)不含to屬性的數(shù)據(jù)流。

              Unauthorized

              這個(gè)表明客戶端的身份請(qǐng)求驗(yàn)證失敗,當(dāng)客戶端發(fā)出錯(cuò)誤的密
            碼或者是不存在的用戶名時(shí)會(huì)發(fā)生這種情況。

              Service Unavailable

              這個(gè)錯(cuò)誤主要發(fā)生在服務(wù)器無(wú)法處理客戶端的請(qǐng)求時(shí),譬如,
            當(dāng)我們要發(fā)送一個(gè)消息給離線好友,但接收者的服務(wù)器不支持離線信息存儲(chǔ)的機(jī)制,就會(huì)返回這個(gè)錯(cuò)誤。

              Remote Server Timeout

              當(dāng)試圖連接一個(gè)服務(wù)器而超時(shí)時(shí)就會(huì)發(fā)生這個(gè)錯(cuò)誤。比如說(shuō)一
            個(gè)不正確的服務(wù)器名稱被指定時(shí)。

              Payment Required

              這個(gè)錯(cuò)誤是為未來(lái)使用制定的,現(xiàn)在不會(huì)發(fā)生。

              Forbidden

              這個(gè)錯(cuò)誤發(fā)生時(shí)表明,服務(wù)器理解客戶端的請(qǐng)求,但拒絕處理
            它。現(xiàn)在主要發(fā)生在當(dāng)注冊(cè)時(shí)密碼存儲(chǔ)錯(cuò)誤時(shí)。

              Not Found

              這個(gè)主要是在服務(wù)器無(wú)法找到與這個(gè)客戶端送來(lái)的數(shù)據(jù)包匹
            配的JabberID時(shí)發(fā)生的。

              Not Allowed

              本錯(cuò)誤主要是當(dāng)服務(wù)器根據(jù)該數(shù)據(jù)包中的JabberID判定本次

              Jabber行為無(wú)效時(shí)產(chǎn)生的,譬如當(dāng)非管理員用戶向服務(wù)器發(fā)送一個(gè)管理員數(shù)據(jù)命令時(shí)。

              Registration Required

              這個(gè)錯(cuò)誤現(xiàn)在尚未開始使用。

              Internal Server Error

              當(dāng)服務(wù)器發(fā)生了未知錯(cuò)誤時(shí),就會(huì)返回這個(gè)error,要防止這
            種情況發(fā)生主要是從客戶端入手,要保證發(fā)送的數(shù)據(jù)包的正確性。

              Invalid Parameter

              無(wú)效的參數(shù)錯(cuò)誤。

              在發(fā)生上述錯(cuò)誤時(shí),_display_error_message()都會(huì)做出正確的處理,實(shí)在有未知的錯(cuò)誤發(fā)生時(shí),也會(huì)提示與管理員聯(lián)系。

              下面一一分析成員函數(shù),先看用戶登錄時(shí)所用的:

              function connect ($server, $port = "5222")
               
              注意這里默認(rèn)的端口為5222。如果你使用了SSL登錄也可以改為5223。函數(shù)里首先是驗(yàn)證傳遞過(guò)來(lái)的參數(shù)的合法性。也就是server,username,password及resource不能為空,否則就報(bào)告錯(cuò)誤。

              接著是與server端的5222端口相連接,這里使用了fsockopen函數(shù),這個(gè)函數(shù)功能很強(qiáng)大,它與服務(wù)器做了一個(gè)TCP連接,并且它返回了一個(gè)文件指針,可用于其他的文件函數(shù)(如fgets、fgetss、fputs、fclose或feof等)。可以說(shuō)沒(méi)有它,jabber的功能就實(shí)現(xiàn)不了,因?yàn)閖abber主要是依靠與server的連接,交互數(shù)據(jù)流來(lái)實(shí)現(xiàn)的,用其他語(yǔ)言如C/C++可以很方便的調(diào)用connect函數(shù)(以及之后的 send、receive函數(shù)),同樣PHP有fsockopen()也很不錯(cuò)。

              登錄時(shí)使用Login ($username, $ password, $resource, $server, $port = "5222"),當(dāng)jabber->connect()打開連接后,開始向server端發(fā)送數(shù)據(jù),譬如登錄時(shí)發(fā)送的XML數(shù)據(jù)包,隨后要讀入返回的流,這時(shí)會(huì)產(chǎn)生一個(gè)錯(cuò)誤,因?yàn)槭褂胒read或fgets等PHP文件操作函數(shù),都要求讀入一定的量字符數(shù)(按照參數(shù)),或者是讀到行尾或文件尾,但是由服務(wù)器返回的數(shù)據(jù)是一個(gè)完整XML流的一部分,沒(méi)有所謂的行分隔,我們預(yù)先也無(wú)法知道此次返回多少字節(jié),如果寫成fgets($fp, 1024)這樣的,就會(huì)使該腳本陷入延時(shí),因?yàn)閒gets行為就是想讀入1024個(gè)字節(jié)或者是到行尾/文件尾,等如果本次數(shù)據(jù)量小于1024字節(jié),就會(huì)陷入這個(gè)函數(shù),不能正確返回值。

              在查閱了php.net的最新函數(shù)后發(fā)現(xiàn),我們可以依靠socket_get_status()函數(shù)的unread_bytes特性來(lái)間接處理,說(shuō)實(shí)話,這個(gè)方法有點(diǎn)勉強(qiáng),但由于PHP語(yǔ)言的限制,實(shí)在沒(méi)有其他方法來(lái)很好的處理它,如果是C/C++,那就很方便了,recv()函數(shù)自己知道收回多少數(shù)據(jù),再不然配合Peek參數(shù)也可以預(yù)知本次數(shù)據(jù)量。

              而使用socket_get_status()方法,就要分兩步做,首先使用fgets()類型的函數(shù)讀取一次數(shù)據(jù)(可以讀一個(gè)字節(jié)),然后再用 unread_bytes得知本次未讀數(shù)據(jù),依據(jù)這個(gè)準(zhǔn)確的字節(jié)數(shù),再調(diào)用fgets()一次就可以全部讀取了。由于要分兩步做,所以效率不是很高的。然后拼接兩次得到的字符串,就有了本次回應(yīng)的數(shù)據(jù)流了。

              收到XML數(shù)據(jù)后就要來(lái)解析它,PHP有很強(qiáng)大的XML解析函數(shù),因?yàn)樗且揽縠xpat做后臺(tái)模塊的。首先要?jiǎng)?chuàng)建一個(gè)XML解析器,就好象與MySql數(shù)據(jù)庫(kù)做連接一樣,都是準(zhǔn)備工作:

              xml_parser_create();//使用缺省編碼ISO=8859-1

              在下面的函數(shù)中都要用到這個(gè)解析器,然后調(diào)用xml_set_element_handler()來(lái)設(shè)置起始及結(jié)束元素的處理,第一個(gè)參數(shù)就是上面說(shuō)到的解析器,第二個(gè)和第三個(gè)是XML特有規(guī)定的函數(shù)處理格式的名稱,主要是:

              StartElementHandler(int parser, string name, string attr)

              第一個(gè)參數(shù)也是解析器,第二個(gè)用于保存XML元素名稱,缺省情況下,它們會(huì)以大寫形式出現(xiàn)。第三個(gè)是數(shù)組,用以保存當(dāng)前元素的屬性及對(duì)應(yīng)值。有了它,可以利用PHP特有的each逐個(gè)讀出來(lái)。

              我們?cè)赟tartElementHandler中將本次要用到的元素屬性賦值,以便下面的調(diào)用判斷,如登錄中就是要對(duì)$jabber_type值是否為result進(jìn)行判斷,如果是表明登錄成功,如果不是那就是登錄失敗了。

              接下來(lái)是GetRoster()行為,使用它可以獲得當(dāng)前用戶的好友列表,我們發(fā)送:

              <iq type="get"><query xmlns="jabber:iq:roster"/></iq>

              給服務(wù)器,即索要當(dāng)前會(huì)話用戶的好友列表,然后服務(wù)器會(huì)返回一系列數(shù)據(jù)流,里面包括了好友的名稱,JID(jabber唯一標(biāo)識(shí),就好象是QQ中的數(shù)字號(hào)碼)以及認(rèn)證狀態(tài),如果還沒(méi)有通過(guò)好友的認(rèn)證,那subscription屬性就會(huì)為none,WellJabber中采用了$jabber-> roster成員變量來(lái)接收這一系列的值。需要注意的是每次成員函數(shù)調(diào)用時(shí)都使用同一個(gè)連接,i.e.$jabber->connect,所以單個(gè)行為不要調(diào)用fclose來(lái)關(guān)閉它,可以在類的析構(gòu)函數(shù)中調(diào)用。

              SenMessage()發(fā)送消息給好友,這里比較簡(jiǎn)單,當(dāng)獲取好友的JID時(shí),發(fā)送相應(yīng)的數(shù)據(jù)流即可,這里要注意的是,發(fā)送人不需要自己填寫,在經(jīng)過(guò)服務(wù)器處理后,會(huì)由服務(wù)器來(lái)添加“from”屬性,這個(gè)是為了防止發(fā)送垃圾信息,前面已經(jīng)說(shuō)過(guò)了。

              最后是登記新的用戶帳號(hào),這里分四步:
             
              首先,要向服務(wù)器發(fā)送一個(gè)連接請(qǐng)求,就如同登錄時(shí)所發(fā)送的一樣;

              接著,客戶端會(huì)收到回應(yīng)的數(shù)據(jù)流,這里包含了重要的id,是標(biāo)識(shí)本次會(huì)話的唯一值;這時(shí),我們要發(fā)送本次想注冊(cè)的用戶名,resource名及密碼,注意這里的<iq>請(qǐng)求要包含上面得到的id,而且密碼應(yīng)該采用加密的形式,但WellJabber只是一個(gè)演示程序,所以采用了明文發(fā)送的形式;

              最后,服務(wù)器返回<iq di=’sesseion id’type=’result’>
            代表本次登記注冊(cè)成功。這樣就完成了一個(gè)新用戶的注冊(cè)。

              然后就可以使用該帳號(hào)進(jìn)行登錄了。注意,這里要重新與服務(wù)器打開一個(gè)連接,原先的連接已經(jīng)不能用來(lái)登錄了。

              PHP版的WellJabber所擁有的功能已經(jīng)描述完了。當(dāng)然,從它來(lái)看Jabber工程只能是管中窺豹,Jabber中許多有用的思想和特點(diǎn)它都沒(méi)有體現(xiàn),譬如說(shuō)實(shí)時(shí)接收、文件交換、郵件轉(zhuǎn)發(fā)、聊天室系統(tǒng)甚至是跨平臺(tái)交流(如mobile)。但由于Jabber開放和易用的特性,我們看到,任何人都可以用自己喜歡的語(yǔ)言去處理jabber、去理解jabber,這么博大包容的特性也許就是它最吸引人的地方,Jabber的前途將無(wú)可限量。

            posted on 2010-01-25 00:09 楊粼波 閱讀(2446) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久久国产一区二区三区| 国产精品久久亚洲不卡动漫| 久久99精品久久久久久水蜜桃| 99精品伊人久久久大香线蕉| 久久一区二区免费播放| 久久人妻无码中文字幕| 久久精品中文字幕久久| 思思久久好好热精品国产| 国产精品久久久久久福利漫画| 久久亚洲色一区二区三区| 日产精品久久久久久久性色| 久久亚洲精品中文字幕三区| 久久亚洲精品无码aⅴ大香| 品成人欧美大片久久国产欧美 | 伊人久久久AV老熟妇色| 国产精品久久久久影院嫩草 | 一级a性色生活片久久无| 狠狠88综合久久久久综合网| 久久久久亚洲精品天堂久久久久久 | 亚洲国产香蕉人人爽成AV片久久 | 色婷婷噜噜久久国产精品12p| 99久久无色码中文字幕| 亚洲精品乱码久久久久久按摩| 久久综合九色综合久99| 久久精品国产秦先生| 久久午夜伦鲁片免费无码| 久久精品国产2020| 亚洲国产精品成人久久蜜臀| 久久99精品久久久久久噜噜| 91精品国产91久久久久久青草| 久久精品国内一区二区三区| 国产成年无码久久久久毛片| 欧美熟妇另类久久久久久不卡| 久久AV无码精品人妻糸列| 一本色道久久88精品综合| 伊人久久大香线蕉亚洲| 亚洲级αV无码毛片久久精品 | 精品人妻伦九区久久AAA片69 | 九九久久精品无码专区| 久久国产精品一区| 香蕉久久夜色精品国产尤物|