天天看點

GLOOX1.0---心跳

改定履曆:

2011-08-25-----------建立文本文檔

通常在用戶端與伺服器之間需要心跳來維系連接配接,XMPP可以通過一個擴充協定XEP-0199來實作用戶端與伺服器端的心跳。XEP-0199規定通過發送命名空間為'urn:xmpp:ping'的iq節XML流來解決這個問題。本文代碼為測試代碼……

本文闡述GLOOX用戶端對伺服器消息的封裝

用戶端向伺服器發送ping消息:

[html] view plain copy print ?

  1. <iqfrom='[email protected]/balcony'to='capulet.lit'id='c2s1'type='get'> <ping xmlns='urn:xmpp:ping'/></iq> 

<iq from='[email protected]/balcony' to='capulet.lit' id='c2s1' type='get'> <ping xmlns='urn:xmpp:ping'/></iq>

伺服器的響應pong:

[html] view plain copy print ?

  1. <iq from='capulet.lit' to='[email protected]/balcony' id='c2s1' type='result'/> 

<iq from='capulet.lit' to='[email protected]/balcony' id='c2s1' type='result'/>

如果伺服器不支援ping命名空間,則必須要傳回一個<service-unavailable/> 的error:

[html] view plain copy print ?

  1. <iq from='capulet.lit' to='[email protected]/balcony' id='c2s1' type='error'>  <ping xmlns='urn:xmpp:ping'/>  <error type='cancel'>    <service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>  </error></iq> 

<iq from='capulet.lit' to='[email protected]/balcony' id='c2s1' type='error'> <ping xmlns='urn:xmpp:ping'/> <error type='cancel'> <service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error></iq>

封裝思路:

在程式中另起一個線程專門用做心跳處理;GLOOX庫裡對XEP-0199的ping發送實作是在ClientBase類裡的一個方法:

void xmppPing ( const JID & to,
EventHandler * eh
)

在說明這個方法之前先介紹GLOOX裡面幾個相關的類:

ClientBase : 這個類裡面用一個方法xmppPing實作XEP-0199 ping消息發送。

EventHandler : ping事件處理器,觀察者,純虛基類。實作其虛函數可以收到Ping響應時得到處理。

EventDispatcher : ping事件分發器,用于注冊及登出EventHandler。

Event : ping事件封裝類。

方法說明:Sends a XMPP Ping (XEP-0199) to the given JID. 即發送一個符合xep-0199規範的ping消息給指定的JID。我們這裡是做對伺服器的心跳,是以這裡的JID就是伺服器的JID;EventHandler是觀察者(設計模式之觀察者模式),在xmppPing的實作裡會将會由EventDispatcher對象将觀察者注冊進去,在得到事件時将由EventDispatcher将事件分發給觀相應的察者處理。是以我們要實作觀察者EventHandler.

觀察者實作:

[cpp] view plain copy print ?

  1. class CEventHandler:public EventHandler 
  2. public: 
  3.     CEventHandler(); 
  4.     virtual ~CEventHandler(); 
  5.     virtual void handleEvent(const Event& event); 
  6.     void increaceHeartBeatCount(void); 
  7.     UINT getHeartBeatCount(){return m_nCount;} 
  8. private: 
  9.     void decreaceHeartBeatCount(void); 
  10.     UINT m_nCount; 
  11. }; 

class CEventHandler:public EventHandler

{

public:

CEventHandler();

virtual ~CEventHandler();

virtual void handleEvent(const Event& event);

void increaceHeartBeatCount(void);

UINT getHeartBeatCount(){return m_nCount;}

private:

void decreaceHeartBeatCount(void);

UINT m_nCount;

};

[cpp] view plain copy print ?

  1. CEventHandler::CEventHandler():m_nCount(0) 
  2. CEventHandler::~CEventHandler() 
  3. void CEventHandler::increaceHeartBeatCount() 
  4.     m_nCount++; 
  5.     return; 
  6. void CEventHandler::decreaceHeartBeatCount() 
  7.     if (m_nCount > 0) 
  8.     { 
  9.         m_nCount--; 
  10.     } 
  11.     return; 
  12. void CEventHandler::handleEvent(const Event& event) 
  13.     std::string sEvent; 
  14.     switch (event.eventType()) 
  15.     { 
  16.     case Event::PingPing:   //! 收到PING消息 
  17.         sEvent = "PingPing"; 
  18.         break; 
  19.     case Event::PingPong:   //! 收到傳回PONG消息,心跳累計次數減1 
  20.         sEvent = "PingPong"; 
  21.         decreaceHeartBeatCount(); 
  22.         break; 
  23.     case Event::PingError:  //!  
  24.         sEvent = "PingError"; 
  25.         break; 
  26.     default: 
  27.         break; 
  28.     } 
  29.     TRACE("handleEvent:-------------%s\n", sEvent.c_str()); 
  30.     return; 

CEventHandler::CEventHandler():m_nCount(0)

{

}

CEventHandler::~CEventHandler()

{

}

void CEventHandler::increaceHeartBeatCount()

{

m_nCount++;

return;

}

void CEventHandler::decreaceHeartBeatCount()

{

if (m_nCount > 0)

{

m_nCount--;

}

return;

}

void CEventHandler::handleEvent(const Event& event)

{

std::string sEvent;

switch (event.eventType())

{

case Event::PingPing: //! 收到PING消息

sEvent = "PingPing";

break;

case Event::PingPong: //! 收到傳回PONG消息,心跳累計次數減1

sEvent = "PingPong";

decreaceHeartBeatCount();

break;

case Event::PingError: //!

sEvent = "PingError";

break;

default:

break;

}

TRACE("handleEvent:-------------%s\n", sEvent.c_str());

return;

}

心跳線程:

[cpp] view plain copy print ?

  1. UINT MessageTest::heartBeatThread(LPVOID lpParam) 
  2.     MessageTest* pThis = (MessageTest*)lpParam; 
  3.     if(NULL == pThis) 
  4.         return -1; 
  5.     CEventHandler* pEventHandler = new CEventHandler(); 
  6.     while (!pThis->m_bDisConnect) 
  7.     { 
  8.         //! 心跳次數大于三次則通知斷鍊重連,本次心跳線程結束 
  9.         if (pEventHandler->getHeartBeatCount() > 3) 
  10.         { 
  11.             break; 
  12.         } 
  13.         pThis->m_client->xmppPing(JID("talk.google.com"), pEventHandler); 
  14.         pEventHandler->increaceHeartBeatCount(); 
  15.         Sleep(10*1000);     //! 發送心跳消息的時間間隔T應由用戶端在登入時由伺服器傳回 
  16.     } 
  17.     delete pEventHandler; 
  18.     TRACE("心跳線程退出\n"); 
  19.     return 0; 

UINT MessageTest::heartBeatThread(LPVOID lpParam)

{

MessageTest* pThis = (MessageTest*)lpParam;

if(NULL == pThis)

return -1;

CEventHandler* pEventHandler = new CEventHandler();

while (!pThis->m_bDisConnect)

{

//! 心跳次數大于三次則通知斷鍊重連,本次心跳線程結束

if (pEventHandler->getHeartBeatCount() > 3)

{

break;

}

pThis->m_client->xmppPing(JID("talk.google.com"), pEventHandler);

pEventHandler->increaceHeartBeatCount();

Sleep(10*1000); //! 發送心跳消息的時間間隔T應由用戶端在登入時由伺服器傳回

}

delete pEventHandler;

TRACE("心跳線程退出\n");

return 0;

}

其它關于心跳的機制,比如心跳時間間隔、斷鍊重連等處理需要根據具體項目來修改以上代碼