青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

牽著老婆滿街逛

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

關于Jabber客戶端

來源:http://mcs.szu.edu.cn/user/shendasky/Article_16190

Jabber客戶端

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

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

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

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


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

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

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

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

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

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

      自己寫出一個XML解析程序是完全有可能的,但幸運的是,有很多標準的XML解析程序(庫)可供我們使用,比如使用PHP編寫的WellJabber 實際上就是利用expat作為解析模塊。這里要注意的一點是,你的解析程序必須能處理任何得到的XML數(shù)據(jù)片段,因為前面已經(jīng)說過,jabber中傳遞的 XML數(shù)據(jù)并非完整的,一個徹底結束的數(shù)據(jù)流(以<stream/>結尾)要到程序注銷時才能出現(xiàn)。

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

      Writing XML
      寫XML數(shù)據(jù)相對來說比較簡單了,但仍要注意必須寫得符合語法要求,少一個引號都可能引起服務器拒絕處理、甚至是斷開連接。


      
  • 登錄/注銷Jabber會話

      Opening the session
      當你打開位于5222(或5333)端口上的socket后,需要發(fā)送一個標準的XML頭,以此來打開一個以<stream>開始的完整jabber會話。

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

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

      這時XML解析器就可以發(fā)揮作用了,它提取并保留當前的id值,因為本次Jabber Session就依靠它來標識了。

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

      具體來說,詢問使用jabber:iq:auth空間名稱和<username>以及<resource>元素來標識用戶的jabber ID和計算機的resource名[JPO 1.6.3] 。

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

      Logging Out

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

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

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

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

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


        
    • 管理好友列表
        
        好友資料(Roster)的管理是一個比較頭疼的事情,至少從現(xiàn)在協(xié)議的描述來看。

        How the roster works

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

        Subscribing & unsubscribing buddies

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

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

        More roster info

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

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

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


      
  • 管理好友列表
      
      好友資料(Roster)的管理是一個比較頭疼的事情,至少從現(xiàn)在協(xié)議的描述來看。

      How the roster works

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

      Subscribing & unsubscribing buddies

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

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

      More roster info

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

  • 發(fā)送信息時,使用一個<message>元素[JPO 1.3],它使用”to”屬性來標識接收者;反之,你接受包含”from”屬性的<message>元素,它標識了發(fā)送者。

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

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

      一個信息還應該包括一個<subject>元素,它標識了本次信息的主題,但顯示與否取決于接收者所使用的客戶端程序。

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

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

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

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

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

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

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

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

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

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

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

    聊  天
      
      Jabber的群組聊天或會議機制允許多人同時進行交流。

      這種多人交流的方式在客戶端實現(xiàn)時是比較復雜的,這是大家所公認的,因為有兩套聊天協(xié)議在使用。群組聊天是最早采用的,而會議機制是新的,也更靈活(注意,現(xiàn)在只有jabber 1.4服務器版本才支持它——做為一個外接模塊)。實際上,協(xié)議本身仍在不段變化,還沒有最終形成標準。

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

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

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

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

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

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

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

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

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

      Chat invitations

      聊天邀請使用包含<xmlns=”jabber:x:conference”>的請求來實現(xiàn)。

      Sending and receiving messages

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

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

      Jabber還支持IRC的“表情”聊天方式,這使聊天者能做出類似舞臺動作的行為。(這個在QQ中是很常見,也很有趣的)客戶端通過前綴”/me”來辨識這樣的信息,通常在顯示前應該插入使用對象的昵稱。

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

      Leaving the conference

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

      File Transfer

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

      OOB不是僅為文件轉送來設計的,它可用來傳送任何URL,比如一個到心愛站點的鏈接,盡管一個HTML消息也可以支持它。

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


      [*}注冊新用戶

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

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

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

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

      如果注冊失敗了,你將得到錯誤的回應,如果錯誤代碼是409(沖突),這意味著你注冊的用戶名是無效的。

      Updating registration

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

      Canceling an account

      如果你需要終止一個帳號,你先得通過發(fā)送一個<iq type=”get”>元素來獲得服務器的<key>,然后再發(fā)送包含<remove>子元素的<iq type=”set”>來達成。


      [*}WellJabber功能模塊

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

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

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

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

      本程序只預計包含五個功能模塊:用戶注冊,用戶登錄,獲取好友列表,發(fā)送信息,用戶注銷。
    考慮到面向對象的特性,WellJabber程序采用了類的定義,以方便腳本調用,支持類是PHP中很有用的特點,特別是數(shù)據(jù)庫操作,如果能把一般SQL行為用類來封裝,那么在修改數(shù)據(jù)庫類型時將會很方便,做到以做少的改動支持最大的兼容性。

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

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

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

      Unauthorized

      這個表明客戶端的身份請求驗證失敗,當客戶端發(fā)出錯誤的密
    碼或者是不存在的用戶名時會發(fā)生這種情況。

      Service Unavailable

      這個錯誤主要發(fā)生在服務器無法處理客戶端的請求時,譬如,
    當我們要發(fā)送一個消息給離線好友,但接收者的服務器不支持離線信息存儲的機制,就會返回這個錯誤。

      Remote Server Timeout

      當試圖連接一個服務器而超時時就會發(fā)生這個錯誤。比如說一
    個不正確的服務器名稱被指定時。

      Payment Required

      這個錯誤是為未來使用制定的,現(xiàn)在不會發(fā)生。

      Forbidden

      這個錯誤發(fā)生時表明,服務器理解客戶端的請求,但拒絕處理
    它。現(xiàn)在主要發(fā)生在當注冊時密碼存儲錯誤時。

      Not Found

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

      Not Allowed

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

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

      Registration Required

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

      Internal Server Error

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

      Invalid Parameter

      無效的參數(shù)錯誤。

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

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

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

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

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

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

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

      收到XML數(shù)據(jù)后就要來解析它,PHP有很強大的XML解析函數(shù),因為它是依靠expat做后臺模塊的。首先要創(chuàng)建一個XML解析器,就好象與MySql數(shù)據(jù)庫做連接一樣,都是準備工作:

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

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

      StartElementHandler(int parser, string name, string attr)

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

      我們在StartElementHandler中將本次要用到的元素屬性賦值,以便下面的調用判斷,如登錄中就是要對$jabber_type值是否為result進行判斷,如果是表明登錄成功,如果不是那就是登錄失敗了。

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

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

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

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

      最后是登記新的用戶帳號,這里分四步:
     
      首先,要向服務器發(fā)送一個連接請求,就如同登錄時所發(fā)送的一樣;

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

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

      然后就可以使用該帳號進行登錄了。注意,這里要重新與服務器打開一個連接,原先的連接已經(jīng)不能用來登錄了。

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

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

    青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲国产精品成人| 久久综合狠狠综合久久综青草| 男女激情久久| 老司机一区二区三区| 在线观看国产一区二区| 美女精品国产| 欧美国产精品va在线观看| 夜夜爽夜夜爽精品视频| 久久精品99无色码中文字幕| 亚洲激情精品| 亚洲精品国精品久久99热| 欧美日韩综合另类| 性色一区二区三区| 麻豆国产精品一区二区三区| 在线视频免费在线观看一区二区| 亚洲午夜未删减在线观看| 黄色国产精品一区二区三区| 亚洲国产日韩一区二区| 国产精品乱看| 欧美激情第10页| 国产精品视频久久一区| 欧美成人亚洲| 国产精品一区二区三区成人| 蜜臀91精品一区二区三区| 欧美日韩国产123区| 欧美在线视频不卡| 欧美激情网友自拍| 欧美一区二区在线播放| 你懂的成人av| 久久九九热免费视频| 欧美极品色图| 免费国产一区二区| 国产精品极品美女粉嫩高清在线 | 欧美精品一区二区三区一线天视频| 亚洲午夜高清视频| 老司机久久99久久精品播放免费 | 欧美亚洲免费在线| 欧美激情视频网站| 久久人人看视频| 国产精品久久久久aaaa樱花| 亚洲国产精品一区二区久| 国产精品久久久久久模特 | 欧美一区二区三区免费看| 欧美精品aa| 欧美第一黄色网| 国产精品久久久久久久免费软件| 亚洲激情综合| 亚洲黄色尤物视频| 久久女同精品一区二区| 欧美永久精品| 国产嫩草影院久久久久| 日韩视频中午一区| 99精品视频一区二区三区| 美女露胸一区二区三区| 老司机凹凸av亚洲导航| 国产一区二区久久精品| 亚洲欧美日韩精品一区二区| 亚洲欧美激情精品一区二区| 欧美日韩一区二区三区| 亚洲精品一区在线| 亚洲精选一区| 欧美国产欧美亚洲国产日韩mv天天看完整 | 午夜影院日韩| 欧美一级在线视频| 国产精品国产三级国产专播品爱网| 亚洲第一级黄色片| 亚洲精品老司机| 男人的天堂亚洲在线| 亚洲激情一区二区| 亚洲美女在线视频| 欧美日韩精品二区| 中文久久精品| 久久精品亚洲热| 一区二区三区在线视频免费观看 | 亚洲国产精品第一区二区三区 | 国产精品www.| 亚洲欧美中文另类| 久久影视三级福利片| 在线观看精品| 欧美区一区二区三区| 一区二区三区高清不卡| 欧美在线视频一区二区| 狠狠狠色丁香婷婷综合激情| 老牛嫩草一区二区三区日本| 亚洲国产一区二区三区a毛片| 国产精品99久久久久久www| 国产精品豆花视频| 久久成人免费视频| 亚洲福利视频三区| 亚洲一区在线免费| 国产日韩在线不卡| 免费在线观看成人av| 一区二区免费在线观看| 久久久噜噜噜久久人人看| 亚洲国产精品成人久久综合一区 | 毛片av中文字幕一区二区| 妖精视频成人观看www| 久久精品一区二区| 一本久久知道综合久久| 国产日韩精品在线| 欧美~级网站不卡| 亚洲男人的天堂在线观看| 欧美成人资源网| 亚洲欧美自拍偷拍| 黄色精品一区| 国产精品日韩欧美大师| 蜜臀久久99精品久久久久久9 | 国产精品久久一区二区三区| 久久久久久有精品国产| 宅男噜噜噜66一区二区| 麻豆国产va免费精品高清在线| 亚洲一区二区视频| 亚洲高清视频一区二区| 国产毛片一区二区| 欧美日韩亚洲成人| 久久一本综合频道| 欧美在线观看日本一区| 正在播放欧美一区| 亚洲黑丝在线| 免费成人性网站| 久久国产精品久久久久久电车| 亚洲免费av片| 亚洲国产日韩欧美在线动漫| 国产亚洲欧美日韩在线一区 | 亚洲激情午夜| 国产一级揄自揄精品视频| 欧美经典一区二区三区| 免费成人高清在线视频| 久久久久久久久岛国免费| 亚洲一区精品视频| 一本久道综合久久精品| 亚洲高清av| 欧美第一黄色网| 欧美国产日产韩国视频| 免费中文字幕日韩欧美| 免费在线视频一区| 免费欧美视频| 欧美高潮视频| 欧美国产亚洲视频| 欧美激情va永久在线播放| 麻豆免费精品视频| 免费看成人av| 欧美成人午夜免费视在线看片| 嫩草成人www欧美| 亚洲国产黄色片| 亚洲国产精品久久久久秋霞不卡| 欧美激情四色| 亚洲国产一区二区三区在线播| 亚洲电影av| 亚洲精品在线免费观看视频| 日韩一级精品视频在线观看| 一本不卡影院| 亚洲伊人网站| 欧美在线亚洲综合一区| 久久男女视频| 欧美高清视频在线| 欧美亚一区二区| 国产日韩精品在线播放| 一区二区三区在线视频观看| 91久久香蕉国产日韩欧美9色 | 在线日韩日本国产亚洲| 亚洲第一在线综合网站| 一本久久a久久精品亚洲| 欧美一级片在线播放| 久久蜜桃精品| 亚洲日韩中文字幕在线播放| 一本色道久久99精品综合| 亚洲免费影视| 美女主播一区| 国产精品99一区| 狠狠色丁香久久综合频道| 亚洲日韩欧美视频| 午夜精品美女自拍福到在线 | 欧美亚洲三区| 欧美国产另类| 午夜亚洲伦理| 欧美精品18videos性欧美| 国产视频在线观看一区 | 狠狠综合久久av一区二区老牛| 亚洲国产精品视频| 午夜在线成人av| 亚洲大片在线观看| 亚洲欧美日韩国产精品| 欧美va亚洲va香蕉在线| 国产九区一区在线| 日韩视频在线免费| 久久久精品日韩| 日韩一二在线观看| 免费视频亚洲| 国内精品美女av在线播放| 亚洲无限av看| 亚洲电影自拍| 久久精品国产一区二区三| 欧美午夜理伦三级在线观看| 亚洲国产精品久久久久| 久久精品夜夜夜夜久久| 正在播放欧美一区| 欧美日本在线看| 亚洲国产va精品久久久不卡综合| 午夜精品久久久|