local Heart = class("Heart" , require("luaScript.Protocol.Protocol")) local HeartCmd = { --[[ * 心跳包 *
	* 请求: {@link HeartBeatRequest}
	* 响应: {@link HeartBeatResponse}
	* 
--]] HEART_BEAT = 0x2008, } -- 服务器返回的心跳包 local HeartBeatResponse = defClass("HeartBeatResponse" -- 服务器的当前时间,从1970开始的毫秒数 , defVar("serverTime", VT_Long, 0) ) -- 每隔多久发一次心跳包 local HeartBeatTime = 5 -- 心跳包多久没有收到就认为超时了 local NetOverTime = 8; function Heart:onLoginToUserProtocol() logD("Heart:onLoginToUserProtocol()") -- 开始发送心跳包 self.net.Socket:setOption("HeartBeatCode" , HeartCmd.HEART_BEAT); self.net.Socket:setOption("HeartBeatTime" , HeartBeatTime * 1000); self:resetNetOverTimer(); end -- 服务器心跳回调 function Heart:onUpdateServerTime(status, response) logD("Heart:onUpdateServerTime()") if status ~= 0 then print("心跳包返回错误代码 statusCode:" .. tostring(status)) return; end; -- 更新 self.heartBeatResponse = response:updateTo(self.heartBeatResponse); self.TimeEclipsed = response.serverTime / 1000; self.TimeStart = os.time(); -- 记录下上次消息时间 self.LastNetMessageTime = self.TimeStart; self:resetNetOverTimer() end function Heart:onNetProcessMessage(event) self.LastNetMessageTime = os.time(); end -- 设置超时定时器 function Heart:resetNetOverTimer() logD("Heart:resetNetOverTimer()") if not tolua.isnull(self.TimeoutAction) then app.mainScene:stopAction(self.TimeoutAction); end self.TimeoutAction = nil; self.NeedToReconnect = false; if app.mainScene then local t1 = os.time() local function onTimeout() logD("Heart:resetNetOverTimer() 心跳超时时间 = ", os.time()) logD("Heart:resetNetOverTimer() 误差超时时间 = ", (os.time()-t1)) -- 两帧之后,再检查是否有收到消息,如果还没收到,就认为超时 local lastTime = self.LastNetMessageTime; local curTime = os.time(); local deltaTime = curTime - lastTime; logD("Heart:resetNetOverTimer() curTime = ", curTime); logD("Heart:resetNetOverTimer() lastTime = ", lastTime); logD("Heart:resetNetOverTimer() deltaTime = ", deltaTime); if deltaTime >= NetOverTime then -- 这里不一定是断线了,如果充值的时候,游戏渲染窗口就不渲染了整个游戏就更新了,网络消息也不会触发脚本了 -- 但是这个时候网络其实是没有断开的 -- 延迟一帧执行,给一次机会 local function reconnectToServer() if self.NeedToReconnect and not app.user.kickOffState then logD("Heart:resetNetOverTimer() 已经[" .. deltaTime .. "]秒没有收到服务器消息了,说明网络有问题,重连咯"); -- 断开网络后 会自动重连 不需要手动调用reconnect self.net:close(); -- 马上重连 --self.net:reConnect(); self.NeedToReconnect = false end end self.NeedToReconnect = true runInNextFrame(reconnectToServer) else -- 说明在定时器期间又收到服务器的消息但没有收到心跳包 -- 再给一次机会,不要断线 runInNextFrame(function() self:resetNetOverTimer() end) end self.TimeoutAction = nil; end logD("Heart:resetNetOverTimer() 心跳开始本地时间 = ", t1); -- 发完心跳包一段时间后还没有新消息,就说明网络死了 self.TimeoutAction = app.mainScene:runActions(cc.DelayTime:create(NetOverTime), onTimeout); end end -- 停止 function Heart:stop() end -- 服务器时间(返回秒数) function Heart:getServerTime() local now = os.time() local seconds = now - self.TimeStart; return math.ceil(self.TimeEclipsed + seconds); end -- 服务器时间(日期形式返回) function Heart:getServerDateTime() return BeijingTime.dateFunc(self:getServerTime()) end --知道已经断开连接停止检测 function Heart:onStopHeart() if not tolua.isnull(self.TimeoutAction) then app.mainScene:stopAction(self.TimeoutAction); end end function Heart:ctor(net) Heart.super.ctor(self , net); self.heartBeatResponse = HeartBeatResponse:new(); -- 上次心跳包服务器时间 self.TimeEclipsed = 0; -- 上次心跳包客户端时间 self.TimeStart = 0; -- 上次更新消息时间 self.LastNetMessageTime = 0 -- 注册网络消息更新事件 app:addEventListener("onRecvMsgFromGameServer" , handler(self , self.onNetProcessMessage)); -- 注册登录事件 app:addEventListener("onGameServerConnected" , handler(self , self.onLoginToUserProtocol)); app:addEventListener("onGameServerDisConnect" , handler(self , self.onStopHeart)); -- 注册心跳回调函数 self:defPullMsg{name = "heartBeat", cmd = HeartCmd.HEART_BEAT , resCmd = HeartCmd.HEART_BEAT, reader = HeartBeatResponse , func = handler(self , self.onUpdateServerTime)}; self:defPushMsg{cmd = HeartCmd.HEART_BEAT , reader = HeartBeatResponse , func = handler(self , self.onUpdateServerTime)}; end return Heart;