Files
Main/Assets/Code/Logic/_Required/Heart/HeartSystem.cs

287 lines
9.3 KiB
C#
Raw Normal View History

2025-01-25 04:38:09 +08:00
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
{
/// <summary>
/// 心跳系统,
/// 这里主要处理与服务器的定时信息发送
/// </summary>
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
}
}