gloox連接至服務器端

在使用gloox之前,有必要先提一下XMPP協議這個東東。

XMPP協議是一個基於互聯網的即時通信標準協議。它採用XML技術,以文本的方式傳輸即時消息。支持動態自定義擴展應用。與傳統的網絡協議相比,如QQ等,XMPP協議並不是一個基於二進制方式實現的協議,而是基於XML技術的文本方式,也就是說如果不採用加密技術的話,是可以直接查看發送的消息的。XMPP協議通過定義一些XML的節點關鍵字,來表明消息發送信息,並與其它協議能夠有效的結合,總的說來,XMPP協議是一種很不錯的準實時消息協議標準。如果允許,你可以自己定義一個協議出來,只要約定了XML節點關鍵字,並考慮了消息交換中的各種情況。但是如果沒有特別的情況,一般應該是採用XMPP協議標準進行消息交換,同時可以根據自己的特定應用,適當擴展一些節點,並根據自行擴展約定,解析之即可。

那麼gloox是用來幹嘛的呢?問題很簡單,根據前面所述,XMPP協議只是一個協議,一個約定,但本身並沒有提供實現方式。也就是說,XMPP協議定義的那些關鍵字以及發送消息等這些是需要實現的,只要按照XMPP協議來做的話,就可以互通消息了。而gloox就是實現了這樣一個協議的開發包,我們可以通過這個開發包,開發自己的應用來。

那麼gloox如何實現了XMPP協議的呢,其實它的底層就是一個socket在收發數據,然後將數據進行XML的解析,封裝就可以了。如果允許的話,你是可以自己做socket通信的,只要連接到XMPP服務器,然後收發消息就可以了,對收到的消息,將其解析成XML格式,然後再獲取需要的信息,對於發消息,也是將要發送的文本消息封裝成XMPP協議定義的關鍵節點,然後利用socket發送就可以了。

當然,如果通過socket通信方式,按XMPP協議要求收發消息是沒有任何問題的,可是說實話,真正能把握socket通信是有一定難度的,雖然看起來就那麼幾個API,要想用好需要時間。而gloox已經做了這一步了,何必要重複發明輪子呢?gloox已經在底層實現了和XMPP服務器的socket通信了,並且提供了二次開發接口,使我們不用考慮底層數據連接等方面的問題,何樂而不爲呢?

好了,前面似乎說了些廢話,但對於一些東西的本質我認爲是有必要清晰的認識一下的,這樣我們可以通過本質看現象,呵呵,反過來用也可以。明白了這一點,在使用gloox的API進行二次開發時,就能知其然,也知其所以然了。

這次先從基本的和XMPP協議服務器連接開始,一步一步來。

其實在下載的gloox開發包中,SRC裏面有example和test兩個目錄,該目錄下有使用的例子,你可以直接看例子,可以明白如何使用的。我也是通過這些例子,再看源代碼中的註釋,明白了一些東西的,然後再整理一下,覺得有些收穫,所以把它寫出來。

要想連接服務器,通常需要下面幾個信息:服務器地址(域名或者IP地址),服務器端口號,用戶帳號,用戶密碼。在XMPP協議中,服務器建議的端口號爲5222,如果沒其它必要,建議採用該端口號。XMPP的用戶帳號別名叫JID,JID 惟一確定進行即時消息和在線狀態信息通信的獨立對象或實體, 並可兼容其他即時通信系統( 如MSN 等) 相應的實體標識及其在線狀態信息。其語法規則爲: [節點″@″] 域名[″/″資源], 其中各個域的長度不能超過1 023 字節, 總長度最大爲3 071 字節。從JID的定義可以看出來,其實要連接到服務器,JID中就已經含有了服務器的地址,而如果默認採用5222端口號的話,則可以不用提供服務器地址和端口就可以了,而只通過JID就可以和服務器連接上。

我使用的服務器是openfire,故我直接通過openfire的管理端在裏面建了幾個用戶,當然gloox提供了向服務器註冊帳號,修改密碼以及刪除帳號的API,不過我這裏暫時不去做這個功能,因爲我覺得在實際的項目開發中意義不大,並且如果能將其它的功能理解了,看一下gloox源碼中的那個註冊的例子,應該是沒有任何問題的。

現在假設我已經註冊了一個用戶名爲:userTest@serverTest/test,密碼爲:testPassword的帳號,後面我將用這個帳號進行和服務器的連接,即登陸。

假設現在你有一個類叫MessageTest,該類中有一個方法叫start(),你打算用這個方法進行登陸,則登陸的代碼如下(代碼中含有解釋):

#include "include/client.h"

#include "include/connectionlistener.h"

#include "include/disco.h"

#include "include/stanza.h"

#include "include/gloox.h"

#include "include/lastactivity.h"

#include "include/connectiontcpclient.h"

using namespace gloox;

#ifndef _WIN32

# include <unistd.h>

#endif

#include <stdio.h>

#include <string>

#if defined( WIN32 ) || defined( _WIN32 )

# include <windows.h>

#endif

//ConnectionListener爲一個連接狀態信息的//監聽器,當連接成功,或者失敗時,都

//會調用該監聽器中的該方法。如果你對連接狀態信息不感興趣,可以不用繼承該

//類,認爲連接肯定是成功的。但一般的使用是,需要繼承該接口,並實現其中的三個

//虛函數。

class MessageTest : public ConnectionListener

{

public:

    MessageTest() {}

    virtual ~MessageTest() {}

    void start()

    {

       //初始化一個JID,即用戶ID

      JID jid( "userTest@serverTest/test" );

//創建一個連接客戶端,後一個參數爲密碼

      j = new Client( jid, "testPassword" );

//註冊連接狀態監聽器,當調用該方法後,

//gloox會在後臺自動調用該接口實現中的相應方法。

      j->registerConnectionListener( this );       //因爲this中實現了ConnectionListener接口

//設置服務,具體意思不詳,照這樣寫就可以了(與服務發現有關)

      j->disco()->setVersion( "messageTest", GLOOX_VERSION, "Linux" );              

      j->disco()->setIdentity( "client", "bot" );

       //關於數字證書認證方面的東東,照抄就行了。

      StringList ca;

      ca.push_back( "/path/to/cacert.crt" );

      j->setCACerts( ca );

      //調用j->connect(false)時,即實現與服務器的連接,即登陸了,連接成功會返回//爲真。Connect函數參數爲false表示不阻塞方式連接,而如果爲真,則爲阻塞//方式連接

      if( j->connect( false ) )

      {       

      }     

    }

    //該該方法即爲實現ConnectionListener監聽器接口中的連接成功的方法實現。

    virtual void onConnect()

    {

      printf( "連接服務器成功!!!/n" );

    }

//該該方法即爲實現ConnectionListener監聽器接口中的連接失敗或者

//斷開網絡的方法實現。

    virtual void onDisconnect( ConnectionError e )

    {

      printf( "斷開連接: %d/n", e );

       delete( j );        

    }

       ///該該方法即爲實現ConnectionListener監聽器接口中的安全連接成功的方法實現。

    virtual bool onTLSConnect( const CertInfo& info )

    {    

      return true;

    }

private:

    Client *j;//客戶端實例對象   

};

int main( int /*argc*/, char** /*argv*/ )//測試代碼

{

MessageTest *r = new MessageTest();

r->start();

delete( r );

return 0;

}

在連接服務器中,只要你創建了一個Client對象實例,你就可以通過該實例操作了。其實獲得一個與服務器的連接,就是獲得一個Client實例對象,只要獲得這個實例對象,就擁有了和服務器的連接(前提是調用了Client對象中的connect()該方法)。

另外還需要注意的是,gloox內部在連接服務器時,如果在約5分鐘內,沒有和服務器互通消息的話,會自動斷開連接的,故需要做一個定時器,在小於5分鐘的時候,向服務器發一個消息,具體的消息一般可以用在線狀態這種類型的消息。我做的時候,是通過一個定時,然後先獲得在席狀態,然後再把這個原原本本的再設置一次就可以了,代碼是這樣的:

Presence pre = client->presence();//client爲創建的那個客戶端對象

client ->setPresence(pre);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章