改定履曆:
2011-08-25-----------建立文本文檔
通常在用戶端與伺服器之間需要心跳來維系連接配接,XMPP可以通過一個擴充協定XEP-0199來實作用戶端與伺服器端的心跳。XEP-0199規定通過發送命名空間為'urn:xmpp:ping'的iq節XML流來解決這個問題。本文代碼為測試代碼……
本文闡述GLOOX用戶端對伺服器消息的封裝
用戶端向伺服器發送ping消息:
[html] view plain copy print ?
- <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 ?
- <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 ?
- <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 ?
- 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;
- };
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 ?
- 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;
- }
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 ?
- 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;
- }
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;
}
其它關于心跳的機制,比如心跳時間間隔、斷鍊重連等處理需要根據具體項目來修改以上代碼