改定履历:
2011-08-25-----------新建文本文档
通常在客户端与服务器之间需要心跳来维系连接,XMPP可以通过一个扩展协议XEP-0199来实现客户端与服务器端的心跳。XEP-0199规定通过发送命名空间为'urn:xmpp:ping'的iq节XML流来解决这个问题。本文代码为测试代码……
本文阐述GLOOX客户端对服务器消息的封装
客户端向服务器发送ping消息:
[html] view plain copy print ?
- <iqfrom='juliet@capulet.lit/balcony'to='capulet.lit'id='c2s1'type='get'> <ping xmlns='urn:xmpp:ping'/></iq>
<iq from='juliet@capulet.lit/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='juliet@capulet.lit/balcony' id='c2s1' type='result'/>
<iq from='capulet.lit' to='juliet@capulet.lit/balcony' id='c2s1' type='result'/>
如果服务器不支持ping命名空间,则必须要返回一个<service-unavailable/> 的error:
[html] view plain copy print ?
- <iq from='capulet.lit' to='juliet@capulet.lit/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='juliet@capulet.lit/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:
- sEvent = "PingPing";
- break;
- case Event::PingPong:
- 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);
- }
- 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; }
其它关于心跳的机制,比如心跳时间间隔、断链重连等处理需要根据具体项目来修改以上代码