Files
Main/Assets/Code/Logic/_Required/Heart/HeartSystem.cs
2025-01-25 04:38:09 +08:00

287 lines
9.3 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}