You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
4.9 KiB

  1. local Heart = class("Heart" , require("luaScript.Protocol.Protocol"))
  2. local HeartCmd = {
  3. --[[
  4. * 心跳包
  5. * <pre>
  6. * 请求: {@link HeartBeatRequest}
  7. * 响应: {@link HeartBeatResponse}
  8. * </pre>
  9. --]]
  10. HEART_BEAT = 0x2008,
  11. }
  12. -- 服务器返回的心跳包
  13. local HeartBeatResponse = defClass("HeartBeatResponse"
  14. -- 服务器的当前时间,从1970开始的毫秒数
  15. , defVar("serverTime", VT_Long, 0)
  16. )
  17. -- 每隔多久发一次心跳包
  18. local HeartBeatTime = 5
  19. -- 心跳包多久没有收到就认为超时了
  20. local NetOverTime = 8;
  21. function Heart:onLoginToUserProtocol()
  22. logD("Heart:onLoginToUserProtocol()")
  23. -- 开始发送心跳包
  24. self.net.Socket:setOption("HeartBeatCode" , HeartCmd.HEART_BEAT);
  25. self.net.Socket:setOption("HeartBeatTime" , HeartBeatTime * 1000);
  26. self:resetNetOverTimer();
  27. end
  28. -- 服务器心跳回调
  29. function Heart:onUpdateServerTime(status, response)
  30. logD("Heart:onUpdateServerTime()")
  31. if status ~= 0 then
  32. print("心跳包返回错误代码 statusCode:" .. tostring(status))
  33. return;
  34. end;
  35. -- 更新
  36. self.heartBeatResponse = response:updateTo(self.heartBeatResponse);
  37. self.TimeEclipsed = response.serverTime / 1000;
  38. self.TimeStart = os.time();
  39. -- 记录下上次消息时间
  40. self.LastNetMessageTime = self.TimeStart;
  41. self:resetNetOverTimer()
  42. end
  43. function Heart:onNetProcessMessage(event)
  44. self.LastNetMessageTime = os.time();
  45. end
  46. -- 设置超时定时器
  47. function Heart:resetNetOverTimer()
  48. logD("Heart:resetNetOverTimer()")
  49. if not tolua.isnull(self.TimeoutAction) then
  50. app.mainScene:stopAction(self.TimeoutAction);
  51. end
  52. self.TimeoutAction = nil;
  53. self.NeedToReconnect = false;
  54. if app.mainScene then
  55. local t1 = os.time()
  56. local function onTimeout()
  57. logD("Heart:resetNetOverTimer() 心跳超时时间 = ", os.time())
  58. logD("Heart:resetNetOverTimer() 误差超时时间 = ", (os.time()-t1))
  59. -- 两帧之后,再检查是否有收到消息,如果还没收到,就认为超时
  60. local lastTime = self.LastNetMessageTime;
  61. local curTime = os.time();
  62. local deltaTime = curTime - lastTime;
  63. logD("Heart:resetNetOverTimer() curTime = ", curTime);
  64. logD("Heart:resetNetOverTimer() lastTime = ", lastTime);
  65. logD("Heart:resetNetOverTimer() deltaTime = ", deltaTime);
  66. if deltaTime >= NetOverTime then
  67. -- 这里不一定是断线了,如果充值的时候,游戏渲染窗口就不渲染了整个游戏就更新了,网络消息也不会触发脚本了
  68. -- 但是这个时候网络其实是没有断开的
  69. -- 延迟一帧执行,给一次机会
  70. local function reconnectToServer()
  71. if self.NeedToReconnect and not app.user.kickOffState then
  72. logD("Heart:resetNetOverTimer() 已经[" .. deltaTime .. "]秒没有收到服务器消息了,说明网络有问题,重连咯");
  73. -- 断开网络后 会自动重连 不需要手动调用reconnect
  74. self.net:close();
  75. -- 马上重连
  76. --self.net:reConnect();
  77. self.NeedToReconnect = false
  78. end
  79. end
  80. self.NeedToReconnect = true
  81. runInNextFrame(reconnectToServer)
  82. else
  83. -- 说明在定时器期间又收到服务器的消息但没有收到心跳包
  84. -- 再给一次机会,不要断线
  85. runInNextFrame(function()
  86. self:resetNetOverTimer()
  87. end)
  88. end
  89. self.TimeoutAction = nil;
  90. end
  91. logD("Heart:resetNetOverTimer() 心跳开始本地时间 = ", t1);
  92. -- 发完心跳包一段时间后还没有新消息,就说明网络死了
  93. self.TimeoutAction = app.mainScene:runActions(cc.DelayTime:create(NetOverTime), onTimeout);
  94. end
  95. end
  96. -- 停止
  97. function Heart:stop()
  98. end
  99. -- 服务器时间(返回秒数)
  100. function Heart:getServerTime()
  101. local now = os.time()
  102. local seconds = now - self.TimeStart;
  103. return math.ceil(self.TimeEclipsed + seconds);
  104. end
  105. -- 服务器时间(日期形式返回)
  106. function Heart:getServerDateTime()
  107. return BeijingTime.dateFunc(self:getServerTime())
  108. end
  109. --知道已经断开连接停止检测
  110. function Heart:onStopHeart()
  111. if not tolua.isnull(self.TimeoutAction) then
  112. app.mainScene:stopAction(self.TimeoutAction);
  113. end
  114. end
  115. function Heart:ctor(net)
  116. Heart.super.ctor(self , net);
  117. self.heartBeatResponse = HeartBeatResponse:new();
  118. -- 上次心跳包服务器时间
  119. self.TimeEclipsed = 0;
  120. -- 上次心跳包客户端时间
  121. self.TimeStart = 0;
  122. -- 上次更新消息时间
  123. self.LastNetMessageTime = 0
  124. -- 注册网络消息更新事件
  125. app:addEventListener("onRecvMsgFromGameServer" , handler(self , self.onNetProcessMessage));
  126. -- 注册登录事件
  127. app:addEventListener("onGameServerConnected" , handler(self , self.onLoginToUserProtocol));
  128. app:addEventListener("onGameServerDisConnect" , handler(self , self.onStopHeart));
  129. -- 注册心跳回调函数
  130. self:defPullMsg{name = "heartBeat", cmd = HeartCmd.HEART_BEAT , resCmd = HeartCmd.HEART_BEAT, reader = HeartBeatResponse , func = handler(self , self.onUpdateServerTime)};
  131. self:defPushMsg{cmd = HeartCmd.HEART_BEAT , reader = HeartBeatResponse , func = handler(self , self.onUpdateServerTime)};
  132. end
  133. return Heart;