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