using System; using System.Collections.Generic; using System.Text; using Thousandto.Core.Base; using Thousandto.Code.Center; using Thousandto.Core.Framework; using UnityEngine; namespace Thousandto.Code.Logic { /// /// 心跳系统, /// 这里主要处理与服务器的定时信息发送 /// public class HeartSystem { //10秒 再加500毫秒的误差,避免误杀,这里的单位是毫米 private const float CN_SEND_HEART_INTERVAL = 10.5f * 1000; //20秒,这里等待返回超时的话,再次发送消息的间隔时间,单位毫秒 private const float CN_SEND_TIMEOUT_HEART_INTERVAL = 20 * 1000; //等待第一次接受数据的超时时间,2分钟 private const float CN_WAIT_FIRST_RECIEVED_TIMEOUT = 2 * 60 * 1000; //做线程锁处理 private static object _lockObj; //统计连续发送心跳的个数 private int _sendHeartMsgCounter = 0; //消息延迟次数 private int _msgDelayTimes = 0; //是否允许心跳线程 private bool _enable = false; //等待服务器应答 private bool _waitServerRespond = false; //普通心跳消息计时器 private float _normalHeartTimer = 0; //发送消息时间 private DateTime _sendTime = DateTime.Now; //接收响应时间 private DateTime _receiveTime = DateTime.Now; //启动时间 private DateTime _enableTime = DateTime.Now; //服务器时间 private double _serverTime = 0f; //切换到后台心跳计时器 private float _inBackgroundTimer = 0f; //切换到后台的系统Tick int _startBackgroundTick = 0; //服务器时区偏移秒数 private int _serverZoneOffset = 0; //服务器同步时间(UTC时间) private double _serverUTCTime = -1; //服务器同步时间(UTC时间) public double ServerTime { get { return _serverUTCTime; } } //服务器时区偏移秒数 public int ServerZoneOffset { get { return _serverZoneOffset; } } //服务器时区时间 public double ServerZoneTime { get { return ServerTime + _serverZoneOffset; } } //网络延迟ping值 public int NetPingValue { get; set; } //是否已经接受到心跳数据 public bool IsReceiveHeart { get; private set; } //测试停止心跳 public bool TestStopReceiveHeart { get; set; } public HeartSystem() { _lockObj = new object(); IsReceiveHeart = false; TestStopReceiveHeart = false; } public void SetServerZoneOffset(int zoneOffset) { _serverZoneOffset = zoneOffset; } //网络线程的心跳处理 public void OnNetworkThreadTick(float deltaByms) { if (_enable == false) return; if (IsReceiveHeart) {//当服务器发送过心跳给客户端就正常心跳逻辑 //根据服务器是否返回,来判断客户端的时间间隔是否正确. if (_waitServerRespond) { NetPingValue += (int)(deltaByms); //这里做超时判断,这里的判断时通过发送时间来判断 var elapse = (DateTime.Now - _sendTime).TotalMilliseconds; if (elapse > CN_SEND_TIMEOUT_HEART_INTERVAL) { SendReqHeartMsg(); } } else { //如果已经接到服务器反馈的消息,那么这里就准备下次的心跳发送 //这里是通过接受消息的时间来判断 var elapse = (DateTime.Now - _receiveTime).TotalMilliseconds; if (elapse >= CN_SEND_HEART_INTERVAL || elapse < 0) { SendReqHeartMsg(); } } } else { //当服务器一直没有发送心跳消息给客户端,那么就需要这里做一下驱动才可以. if ((DateTime.Now - _enableTime).TotalMilliseconds > CN_WAIT_FIRST_RECIEVED_TIMEOUT) { _enableTime = DateTime.Now; SendReqHeartMsg(); } } } //通过Unity的心跳来处理 public void Update(float delta) { //计算当前帧的服务器时间 _serverUTCTime = _serverTime + (DateTime.Now - _receiveTime).TotalSeconds; if (_enable) { //这里判断是否需要重连 CheckNeedReconnect(); } } //开启心跳处理 public void EnabelHeartMsg(bool enable) { Debug.Log("心跳设置:"+enable); _enable = enable; _sendHeartMsgCounter = 0; _msgDelayTimes = 0; _enableTime = DateTime.Now; if (enable) { GameCenter.Networker.RecordMsgTagTime = Time.realtimeSinceStartup; } } public void Uninitialize() { IsReceiveHeart = false; EnabelHeartMsg(false); } //打断网络,启动重连 private bool CheckNeedReconnect() { //客户端发送了3次心跳都没收到服务器返回,则主动断掉socket if (_msgDelayTimes > 3) { //开启断线重连的话就复位计数 _msgDelayTimes = 0; if ( !Application.isEditor) {//编辑器状态下不进入断线重连状态 //游戏主场景才做主动断线操作 if (GameCenter.GameStateSystem != null && GameCenter.GameStateSystem.IsCurState((int)GameStateId.World)) { //停止心跳监听 _enable = false; Debug.LogError("服务器心跳无反馈,启动断线重连机制."); GameCenter.Networker.Disconnect(); GameCenter.ReconnectSystem.Reconnect(); return true; } } else { Debug.LogError("判断重连,但因为是编辑器下所以不进行重连处理."); } } return false; } #region//网络通讯 //往服务器发送请求退出的消息 public void SendReqQuit() { MSG_Register.ReqQuit req = new MSG_Register.ReqQuit(); req.Send(); IsReceiveHeart = false; _sendHeartMsgCounter = 0; } //发送一个特殊心跳信息,让服务器重新倒计时 public void SendReqReallyHeartMsg() { MSG_heart.ReqReallyHeart normalHeartReq = new MSG_heart.ReqReallyHeart(); normalHeartReq.Send(); } //发送普通心跳同步信息 public void SendReqHeartMsg() { MSG_heart.ReqHeart req = new MSG_heart.ReqHeart(); req.time = TimeUtils.GetNow(); req.Send(); //记录最后一次发送时间 _sendTime = DateTime.Now; //记录发送次数 _sendHeartMsgCounter++; //等待服务器应答 _waitServerRespond = true; //消息延迟的次数 _msgDelayTimes++; //Debug.LogError("SendReqHeartMsg::" + _sendTime.ToFileTimeUtc() + ";;" + _msgDelayTimes); } //收到服务器下发的用于检测加速器的消息,这个时候开始进行倒计时 public void OnHearMsgReceive(MSG_heart.ResHeart result) { if (!TestStopReceiveHeart) { //当接受到回复消息,那么延迟次数就设置为0 _msgDelayTimes = 0; //这里设置不用等待了 _waitServerRespond = false; _serverTime = result.serverTime; _receiveTime = DateTime.Now; if (_sendHeartMsgCounter == 0) { //第一次获取,这里给一个随机值 NetPingValue = new System.Random().Next(1, 50); } else { //从发送开始到接收为止,计算延迟 NetPingValue = (int)(_receiveTime - _sendTime).TotalMilliseconds; //Debug.LogError("OnHearMsgRecie:::"+ _sendTime.ToFileTimeUtc()+ ";;" + _receiveTime.ToFileTimeUtc()+ ";;;" + NetPingValue); } _serverUTCTime = _serverTime + (DateTime.Now - _receiveTime).TotalSeconds; IsReceiveHeart = true; } //Debug.LogError("OnHearMsgReceive(MSG_heart.ResHeart result)::" + _receiveTime); } #endregion } }