使用示例
// ************************************************************
// ************************************************************
auto heartBeat = new HeartBeat; // 新建一个心跳
heartBeat->setTimeGap( 3.0f )
->setTimeOut( 5.0f );
// 当heart beat计时超过TimeGap,状态切换为Checking,触发onGapTimeOut。
// 如果没有及时reset,计时超过timeOut,则状态切换为Broken,触发onHeartBroken,表示确定没有心跳了
heartBeat->onGapTimeOut = [&]()
{
// 表示socket一直没有收到消息,已经超时
// 一般地,我们应该在这里主动发送一个心跳包
CCLOG( "gap time out, we should send a heart beat" );
};
heartBeat->onHeartBroken = [&]()
{
// 表示接收心跳包超时,这时我们一般会主动关闭连接,并多次尝试重连
// 如果还是重连失败,则意味着无法访问当前网络。
CCLOG( "heart beat broken. there's problem with the network." );
};
// ************************************************************
// ************************************************************
WebSocket* websocket = new WebSocket();
websocket->init(......); // 发起连接
websocket.onOpen = [](){ // 连接成功
heartBeat->start(); // 心跳开始计时
};
websocket.onMessage = [](){ // 收到消息
heartBeat->reset(); // 收到一个消息,表示网络正常,重置心跳的计时时间和状态
};
websocket.onError = [](){ // 消息出错
};
websocket.onClose = [](){ // 消息出错
heartBeat->reset(); // 链接关闭,停止心跳
};
HeartBeat.h
class HeartBeat : public cocos2d::Ref
{
enum Status
{
STOP,
Beating,
Checking,
Broken,
DEFAULT = STOP,
};
public:
HeartBeat();
~HeartBeat();
HeartBeat* start();
HeartBeat* stop();
HeartBeat* reset();
HeartBeat* setTimeGap( const float &timegap );
HeartBeat* setTimeOut( const float &timeout );
std::function<void()> onGapTimeOut;
std::function<void()> onHeartBroken;
private:
void update( float dt );
private:
float _timeGap;
float _timeOut;
float _lastBeatInterval;
Status _status;
};
HeartBeat.cpp
HeartBeat::HeartBeat() :
_lastBeatInterval( -1 ),
_status( Status::DEFAULT ),
_timeGap( 5.0f ),
_timeOut( 5.0f )
{
cocos2d::Director::getInstance()->getScheduler()->schedule(
CC_SCHEDULE_SELECTOR( HeartBeat::update ), this,
1.0f, // 每秒执行1次
CC_REPEAT_FOREVER, // 一直重复
0.0, // 0.0s后开始执行第1次
true ); // 初始状态是pause
}
HeartBeat::~HeartBeat()
{
_lastBeatInterval = 0.0f;
_status = STOP;
cocos2d::Director::getInstance()->getScheduler()->unschedule( CC_SCHEDULE_SELECTOR( HeartBeat::update ), this );
}
HeartBeat* HeartBeat::start()
{
if( _status != Beating )
{
_status = Beating;
_lastBeatInterval = 0.0f;
cocos2d::Director::getInstance()->getScheduler()->resumeTarget( this );
}
return this;
}
HeartBeat* HeartBeat::stop()
{
if( _status != STOP )
{
_status = STOP;
_lastBeatInterval = 0.0f;
cocos2d::Director::getInstance()->getScheduler()->pauseTarget( this );
}
return this;
}
HeartBeat* HeartBeat::reset()
{
switch( _status )
{
case HeartBeat::Beating:
case HeartBeat::Checking:
{
_lastBeatInterval = 0.0f;
_status = Beating;
}
break;
}
return this;
}
HeartBeat* HeartBeat::setTimeGap( const float &timegap )
{
_timeGap = timegap;
return this;
}
HeartBeat* HeartBeat::setTimeOut( const float &timeout )
{
_timeOut = timeout;
return this;
}
void HeartBeat::update( float dt )
{
switch( _status )
{
case Beating:
{
if( _lastBeatInterval + dt > _timeGap )
{
_status = Checking;
_lastBeatInterval = 0.0f;
if( onGapTimeOut )
{
onGapTimeOut();
}
}
else
{
_lastBeatInterval += dt;
}
}
break;
case Checking:
{
if( _lastBeatInterval + dt > _timeOut )
{
_status = Broken;
_lastBeatInterval = 0.0f;
if( onHeartBroken )
{
onHeartBroken();
}
}
else
{
_lastBeatInterval += dt;
}
}
break;
default:
break;
}
}