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