提交网络模块TCP 超时重连机制

提交网络模块TCP 超时重连机制
This commit is contained in:
ALEXTANG
2022-05-23 17:28:32 +08:00
parent fad0796857
commit c57769605c
17 changed files with 3405 additions and 14 deletions

View File

@@ -41,6 +41,7 @@ public class TEngineUI : UIWindow
protected override void OnUpdate()
{
TEngineHotUpdate.GameLogicMain.Update();
TLogger.LogInfo("TEngineUI OnUpdate");
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using TEngineCore;
namespace TEngineHotUpdate
{
@@ -12,32 +6,32 @@ namespace TEngineHotUpdate
{
public static void Init()
{
Debug.Log("Init");
GameTime.StartFrame();
}
public static void Start()
{
Debug.Log("Start");
GameTime.StartFrame();
}
public static void Update()
{
Debug.Log("Update");
GameTime.StartFrame();
}
public static void LateUpdate()
{
Debug.Log("LateUpdate");
GameTime.StartFrame();
}
public static void Destroy()
{
GameTime.StartFrame();
}
public static void OnApplicationPause(bool isPause)
{
GameTime.StartFrame();
}
}
}

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="15.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -56,6 +57,12 @@
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>UnityLib\UnityEngine.InputLegacyModule.dll</HintPath>
</Reference>
<Reference Include="protobuf-net">
<HintPath>UnityLib\protobuf-net.dll</HintPath>
</Reference>
<Reference Include="protobuf-net">
<HintPath>UnityLib\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
@@ -68,6 +75,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="src\GameLogic\" />
<Folder Include="src\Proto\" />
<Folder Include="src\TEngineCore\3rd\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
using UnityEngine;
namespace TEngineCore
{
public static class GameTime
{
public static void StartFrame()
{
time = Time.time;
deltaTime = Time.deltaTime;
quickRealTime = Time.realtimeSinceStartup;
frameCount = Time.frameCount;
unscaledTime = Time.unscaledTime;
}
public static float time;
public static float deltaTime;
public static int frameCount;
public static float unscaledTime;
public static float realtimeSinceStartup
{
get
{
return Time.realtimeSinceStartup;
}
}
public static float quickRealTime;
}
}

View File

@@ -0,0 +1,166 @@
namespace TEngineCore.Net
{
enum ClientConnectWatcherStatus
{
StatusInit,
StatusReconnectAuto,
StatusReconnectConfirm,
StatusWaitExit
}
class ClientConnectWatcher
{
#region Propreties
private GameClient m_client;
private float m_statusTime;
private int m_reconnetCnt = 0;
private int m_disconnectReason = 0;
private ClientConnectWatcherStatus m_status = ClientConnectWatcherStatus.StatusInit;
private bool m_enable = false;
public bool Enable
{
get { return m_enable; }
set
{
if (m_enable != value)
{
m_enable = value;
if (m_enable)
{
OnEnable();
}
else
{
OnDisable();
}
}
}
}
ClientConnectWatcherStatus Status
{
get { return m_status; }
set
{
if (m_status != value)
{
m_status = value;
m_statusTime = GameTime.time;
}
}
}
#endregion
public ClientConnectWatcher(GameClient client)
{
m_client = client;
m_statusTime = GameTime.time;
m_status = ClientConnectWatcherStatus.StatusInit;
}
public void Update()
{
if (!m_enable)
{
return;
}
if (m_client.IsEntered)
{
return;
}
switch (m_status)
{
case ClientConnectWatcherStatus.StatusInit:
UpdateOnInitStatus();
break;
case ClientConnectWatcherStatus.StatusReconnectAuto:
UpdateOnReconnectAuto();
break;
case ClientConnectWatcherStatus.StatusReconnectConfirm:
UpdateOnReconnectConfirm();
break;
case ClientConnectWatcherStatus.StatusWaitExit:
UpdateOnWaitExit();
break;
default:
break;
}
}
public void OnReConnect()
{
if (m_status == ClientConnectWatcherStatus.StatusReconnectConfirm)
{
Status = ClientConnectWatcherStatus.StatusReconnectAuto;
}
}
void UpdateOnInitStatus()
{
if (m_reconnetCnt <= 2)
{
if (m_reconnetCnt == 0)
{
m_disconnectReason = m_client.LastNetErrCode;
}
Status = ClientConnectWatcherStatus.StatusReconnectAuto;
m_reconnetCnt++;
//Reconnect
m_client.Reconnect();
}
else
{
Status = ClientConnectWatcherStatus.StatusReconnectConfirm;
m_reconnetCnt++;
//var window = UISys.Mgr.ShowWindow<Tip_NetError>();
//window.SetErrCode(m_disconnectReason);
}
}
void UpdateOnReconnectAuto()
{
if (m_client.IsEntered)
{
Status = ClientConnectWatcherStatus.StatusInit;
m_reconnetCnt = 0;
return;
}
float nowTime = GameTime.time;
if (m_statusTime + 5 < nowTime)
{
//切换到默认的,下一帧继续判断是否需要自动还是手动
Status = ClientConnectWatcherStatus.StatusInit;
return;
}
}
void UpdateOnReconnectConfirm()
{
}
void UpdateOnWaitExit()
{
}
private void OnDisable()
{
Status = ClientConnectWatcherStatus.StatusInit;
m_reconnetCnt = 0;
}
private void OnEnable()
{
Status = ClientConnectWatcherStatus.StatusInit;
m_reconnetCnt = 0;
}
}
}

View File

@@ -0,0 +1,118 @@
using System;
using System.Net;
using System.Net.Sockets;
namespace TEngineCore.Net
{
public enum ClientSocketEventType
{
EventConnected,
EventConnectFail,
EventDisconnected,
}
public interface IClientSocket
{
/// <summary>
/// 是否连接了
/// </summary>
bool IsConnected { get; }
/// <summary>
/// 是否是流协议
/// </summary>
bool IsStream { get; }
/// <summary>
/// 心跳间隔
/// </summary>
int HeartBeatInterval { get; }
/// <summary>
/// 本地绑定地址
/// </summary>
EndPoint LocalAddr { get; }
SocketError LastSockError { get; }
string LastErrDesc { get; }
/// <summary>
/// 注册系统事件
/// </summary>
/// <param name="handler"></param>
void RegEventHandle(Action<ClientSocketEventType> handler);
/// <summary>
/// 连接请求
/// </summary>
/// <param name="server"></param>
/// <param name="port"></param>
/// <param name="iTimeout"></param>
/// <param name="retryNum"></param>
/// <returns></returns>
bool Connect(string server, int port, int iTimeout, int retryNum);
/// <summary>
/// 关闭连接
/// </summary>
void Close();
/// <summary>
/// 关闭连接
/// </summary>
void Shutdown();
/// <summary>
/// 发送数据
/// </summary>
/// <returns></returns>
bool Send(byte[] data, int offset, int len);
/// <summary>
/// 发送快捷数据,不用保证丢包
/// </summary>
/// <param name="data"></param>
/// <param name="offset"></param>
/// <param name="len"></param>
/// <returns></returns>
bool SendUdpTypeData(byte[] data, int offset, int len);
/// <summary>
/// 是否支持udp的包
/// </summary>
/// <returns></returns>
bool IsSupportUdpType();
/// <summary>
/// 收包处理
/// </summary>
/// <param name="buf"></param>
/// <param name="iOffset"></param>
/// <param name="maxSize"></param>
/// <returns></returns>
int Recv(byte[] buf, int iOffset, int maxSize);
/// <summary>
/// 循环调用
/// </summary>
void Update();
/// <summary>
/// 最后一帧,保证肯定要包发出去,减少延迟
/// </summary>
void LateUpdate();
/// <summary>
/// 获取写队列的个数
/// </summary>
/// <returns></returns>
int GetSendQueueCount();
/// <summary>
/// 像底层注册错误打印,当缓冲区满之类的,调用上层的统计来打印
/// </summary>
/// <param name="debugCmd"></param>
void RegDebugCmdHandle(Action debugCmd);
}
}

View File

@@ -0,0 +1,117 @@

using System;
using System.Linq;
using Google.Protobuf;
using TEngineProto;
namespace TEngineCore.Net
{
public class Message
{
private const int BufferHead = 4;
private static byte[] buffer = new byte[1024];
private int startindex;
public byte[] Buffer
{
get { return buffer; }
}
public int StartIndex
{
get { return startindex; }
}
public int Remsize
{
get { return buffer.Length - startindex; }
}
public void ReadBuffer(byte[] bufBytes, Action<MainPack> handleResponse = null)
{
var length = bufBytes.Length;
for (int i = 0; i < length; i++)
{
Buffer[i] = bufBytes[i];
}
startindex += length;
if (startindex <= BufferHead)
{
return;
}
int count = length - BufferHead;
while (true)
{
if (startindex >= (count + BufferHead))
{
MainPack pack = (MainPack)MainPack.Descriptor.Parser.ParseFrom(buffer, BufferHead, count);
if (handleResponse != null)
{
handleResponse(pack);
}
Array.Copy(buffer, length, buffer, 0, startindex - length);
startindex -= length;
}
else
{
break;
}
}
}
public void ReadBuffer(int length, Action<MainPack> handleResponse = null)
{
startindex += length;
if (startindex <= BufferHead)
{
return;
}
int count = length - BufferHead;
while (true)
{
if (startindex >= (count + BufferHead))
{
MainPack pack = (MainPack)MainPack.Descriptor.Parser.ParseFrom(buffer, BufferHead, count);
if (handleResponse != null)
{
handleResponse(pack);
}
Array.Copy(buffer, length, buffer, 0, startindex - length);
startindex -= length;
}
else
{
break;
}
}
}
public static byte[] PackData(MainPack pack)
{
byte[] data = pack.ToByteArray();
byte[] head = BitConverter.GetBytes(data.Length);
return head.Concat(data).ToArray();
}
public static byte[] PackDataUdp(MainPack pack)
{
return pack.ToByteArray();
}
}
}

View File

@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using TEngineProto;
namespace TEngineCore.Net
{
public class TcpConnection
{
private Socket socket;
private string m_Host;
private int m_Port;
private Message message;
private GameClient gameClient;
public TcpConnection(GameClient gameClient)
{
message = new Message();
this.gameClient = gameClient;
}
public bool Connect(string host, int port)
{
if (socket == null)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
else
{
if (socket.Connected)
{
socket.Close();
}
}
TLogger.LogInfo("start connect server[{0}:{1}]...", host, port);
gameClient.Status = GameClientStatus.StatusInit;
try
{
socket.Connect(host, port);
StartReceive();
gameClient.Status = GameClientStatus.StatusConnect;
}
catch (Exception e)
{
TLogger.LogError(e.Message);
TLogger.LogError("socket connect {0}:{1} failed", host, port);
//ChangeStateOnEnterFail();
return false;
}
m_Host = host;
m_Port = port;
return true;
}
void StartReceive()
{
socket.BeginReceive(message.Buffer, message.StartIndex, message.Remsize, SocketFlags.None, ReceiveCallback, null);
}
void ReceiveCallback(IAsyncResult asyncResult)
{
try
{
if (socket == null || socket.Connected == false)
{
return;
}
int Length = socket.EndReceive(asyncResult);
if (Length == 0)
{
Close();
return;
}
message.ReadBuffer(Length, gameClient.HandleResponse);
StartReceive();
}
catch (Exception e)
{
TLogger.LogError("TcpConnection DisConnected: " + e);
Close();
}
}
public bool SendCsMsg(MainPack mainPack)
{
if (socket == null || socket.Connected == false)
{
return false;
}
try
{
socket.Send(Message.PackData(mainPack));
return true;
}
catch (Exception e)
{
TLogger.LogError("TcpConnection SendCsMsg: " + e);
return false;
}
}
public void Close()
{
if (socket != null && socket.Connected)
{
socket.Close();
}
gameClient.Status = GameClientStatus.StatusInit;
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TEngineCore.Net
{
public class UdpConnection
{
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TEngineCore.Net
{
/// <summary>
/// 数据中心系统
/// </summary>
public class DataCenterSys : BaseLogicSys<DataCenterSys>
{
private List<IDataCenterModule> m_listModule = new List<IDataCenterModule>();
public override bool OnInit()
{
RegCmdHandle();
InitModule();
return true;
}
private void RegCmdHandle()
{
}
void InitModule()
{
//InitModule(LoginDataMgr.Instance);
}
public void InitModule(IDataCenterModule module)
{
if (!m_listModule.Contains(module))
{
module.Init();
m_listModule.Add(module);
}
}
}
}

View File

@@ -0,0 +1,568 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TEngineProto;
using UnityEngine;
namespace TEngineCore.Net
{
/// <summary>
/// 客户端状态
/// </summary>
public enum GameClientStatus
{
StatusInit, //初始化
StatusReconnect, //重新连接
StatusClose, //断开连接
StatusConnect, //连接中
StatusEnter, //Login登录成功
}
public delegate void CsMsgDelegate(MainPack mainPack);
public class GameClient:TSingleton<GameClient>
{
#region Propriety
#region TimeOutCheck
private const int CHECK_TIMEOUT_PERFRAME = 10;
const int MAX_MSG_HANDLE = 256;
UInt32 m_dwLastCheckIndex = 0;
CsMsgDelegate[] m_aMsgHandles = new CsMsgDelegate[MAX_MSG_HANDLE];
float[] m_fMsgRegTime = new float[MAX_MSG_HANDLE];
private float m_timeout = 15;
#endregion
private string m_lastHost = null;
private int m_lastPort = 0;
private GameClientStatus m_status = GameClientStatus.StatusInit;
/// <summary>
/// GameClient状态
/// </summary>
public GameClientStatus Status
{
get
{
return m_status;
}
set
{
m_status = value;
}
}
/// <summary>
/// 最新连接错误的时间
/// </summary>
private float m_lastLogDisconnectErrTime = 0f;
/// <summary>
/// 最新的错误码
/// </summary>
private int m_lastNetErrCode = 0;
/// <summary>
/// 最近一次心跳的时间
/// </summary>
private float m_lastHbTime = 0f;
/// <summary>
/// 心跳间隔
/// </summary>
private const float m_heartBeatDurTime = 15;
/// <summary>
/// 连续心跳超时
/// </summary>
private int m_heatBeatTimeoutNum = 0;
private int m_ping = -1;
public bool IsEntered
{
get { return m_status == GameClientStatus.StatusEnter; }
}
public bool IsNetworkOkAndLogined
{
get
{
return m_status == GameClientStatus.StatusEnter;
}
}
public int LastNetErrCode
{
get { return m_lastNetErrCode; }
}
private ClientConnectWatcher m_connectWatcher;
private void ResetParam()
{
m_lastLogDisconnectErrTime = 0f;
m_heatBeatTimeoutNum = 0;
m_lastHbTime = 0f;
m_ping = -1;
m_lastNetErrCode = 0;
}
#endregion
private TcpConnection m_connect;
public GameClient()
{
m_connect = new TcpConnection(this);
m_connectWatcher = new ClientConnectWatcher(this);
}
public bool Connect(string host, int port, bool reconnect = false)
{
ResetParam();
if (!reconnect)
{
SetWatchReconnect(false);
}
//GameEventMgr.Instance.Send(ShowWaitingUI);
m_lastHost = host;
m_lastPort = port;
Status = reconnect ? GameClientStatus.StatusReconnect : GameClientStatus.StatusInit;
TLogger.LogWarning("Start connect server {0}:{1} Reconnect:{2}", host, port, reconnect);
return m_connect.Connect(host, port);
}
public void Shutdown()
{
m_connect.Close();
m_status = GameClientStatus.StatusInit;
}
#region
/// <summary>
/// 发送消息包
/// </summary>
/// <param name="reqPkg"></param>
/// <returns></returns>
public bool SendCsMsg(MainPack reqPkg)
{
if (!CheckPack(reqPkg))
{
return false;
}
return DoSendData(reqPkg);
}
/// <summary>
/// 发送消息包并注册回调
/// </summary>
/// <param name="pack"></param>
/// <param name="resHandler"></param>
/// <param name="needShowWaitUI"></param>
/// <returns></returns>
public bool SendCsMsg(MainPack pack, CsMsgDelegate resHandler = null, bool needShowWaitUI = true)
{
if (!CheckPack(pack))
{
return false;
}
var ret = DoSendData(pack);
if (!ret)
{
TLogger.LogError("SendCSMsg Error");
}
else
{
if (resHandler != null)
{
RegTimeOutHandle((uint)pack.Actioncode, resHandler);
RegActionHandle((int)pack.Actioncode, resHandler);
}
}
return ret;
}
private bool DoSendData(MainPack reqPkg)
{
var sendRet = m_connect.SendCsMsg(reqPkg);
return sendRet;
}
#endregion
#region 线
Dictionary<int, List<CsMsgDelegate>> m_mapCmdHandle = new Dictionary<int, List<CsMsgDelegate>>();
/// <summary>
/// 委托缓存堆栈
/// </summary>
private Queue<List<CsMsgDelegate>> cachelistHandle = new Queue<List<CsMsgDelegate>>();
/// <summary>
/// 消息包缓存堆栈
/// </summary>
private Queue<MainPack> queuepPacks = new Queue<MainPack>();
/// <summary>
/// 网络消息回调,非主线程
/// </summary>
/// <param name="pack"></param>
public void HandleResponse(MainPack pack)
{
lock (cachelistHandle)
{
List<CsMsgDelegate> listHandle;
if (m_mapCmdHandle.TryGetValue((int)pack.Actioncode, out listHandle))
{
cachelistHandle.Enqueue(listHandle);
queuepPacks.Enqueue(pack);
}
}
}
/// <summary>
/// Udp网络消息回调非主线程
/// </summary>
/// <param name="pack"></param>
private void UdpHandleResponse(MainPack pack)
{
//Debug.Log(pack);
List<CsMsgDelegate> listHandle;
if (m_mapCmdHandle.TryGetValue((int)pack.Actioncode, out listHandle))
{
foreach (CsMsgDelegate handle in listHandle)
{
handle(pack);
}
}
}
#endregion
#region
/// <summary>
/// 注册静态消息
/// </summary>
/// <param name="iCmdID"></param>
/// <param name="msgDelegate"></param>
public void RegActionHandle(int actionId, CsMsgDelegate msgDelegate)
{
List<CsMsgDelegate> listHandle;
if (!m_mapCmdHandle.TryGetValue(actionId, out listHandle))
{
listHandle = new List<CsMsgDelegate>();
m_mapCmdHandle[actionId] = listHandle;
}
if (listHandle != null)
{
if (listHandle.Contains(msgDelegate))
{
Debug.LogFormat("-------------repeat RegCmdHandle ActionCode:{0}-----------", (ActionCode)actionId);
}
listHandle.Add(msgDelegate);
}
}
/// <summary>
/// 注册Udp静态消息
/// </summary>
/// <param name="iCmdID"></param>
/// <param name="msgDelegate"></param>
public void UdpRegActionHandle(int actionId, CsMsgDelegate msgDelegate)
{
List<CsMsgDelegate> listHandle;
if (!m_mapCmdHandle.TryGetValue(actionId, out listHandle))
{
listHandle = new List<CsMsgDelegate>();
m_mapCmdHandle[actionId] = listHandle;
}
if (listHandle != null)
{
if (listHandle.Contains(msgDelegate))
{
Debug.LogFormat("-------------repeat RegCmdHandle ActionCode:{0}-----------", (ActionCode)actionId);
}
listHandle.Add(msgDelegate);
}
}
/// <summary>
/// 移除消息处理函数
/// </summary>
/// <param name="cmdId"></param>
/// <param name="msgDelegate"></param>
public void RmvCmdHandle(int actionId, CsMsgDelegate msgDelegate)
{
List<CsMsgDelegate> listHandle;
if (!m_mapCmdHandle.TryGetValue(actionId, out listHandle))
{
return;
}
if (listHandle != null)
{
listHandle.Remove(msgDelegate);
}
}
private bool CheckPack(MainPack pack)
{
if (pack == null)
{
return false;
}
if (pack.Actioncode == ActionCode.ActionNone)
{
return false;
}
if (pack.Requestcode == RequestCode.RequestNone)
{
return false;
}
return true;
}
#endregion
#region
protected bool CheckHeatBeatTimeout()
{
if (m_heatBeatTimeoutNum >= 2)
{
Shutdown();
m_heatBeatTimeoutNum = 0;
Status = GameClientStatus.StatusClose;
TLogger.LogError("heat beat detect timeout");
return false;
}
return true;
}
void TickHeartBeat()
{
if (Status != GameClientStatus.StatusEnter)
{
return;
}
var nowTime = GameTime.realtimeSinceStartup;
if (m_lastHbTime + m_heartBeatDurTime < nowTime)
{
m_lastHbTime = nowTime;
MainPack pack = new MainPack
{
Actioncode = ActionCode.HeartBeat
};
GameClient.Instance.SendCsMsg(pack, HandleHeatBeatRes);
}
}
void HandleHeatBeatRes(MainPack mainPack)
{
if (mainPack.Returncode != ReturnCode.Success)
{
//如果是超时了,则标记最近收到包的次数
if (mainPack.Returncode == ReturnCode.MsgTimeOut)
{
m_heatBeatTimeoutNum++;
TLogger.LogError("heat beat timeout: {0}", m_heatBeatTimeoutNum);
}
}
else
{
float diffTime = GameTime.realtimeSinceStartup - mainPack.HeatEchoTime;
m_ping = (int)(diffTime * 1000);
m_heatBeatTimeoutNum = 0;
}
}
#endregion
/// <summary>
/// 清理所有的网络消息
/// </summary>
public void CleanAllNetMsg()
{
m_mapCmdHandle.Clear();
}
public void Reconnect()
{
m_connectWatcher.OnReConnect();
Connect(m_lastHost, m_lastPort, true);
}
public void OnUpdate()
{
HandleCsMsgOnUpdate();
CheckCsMsgTimeOut();
TickHeartBeat();
CheckHeatBeatTimeout();
m_connectWatcher.Update();
}
#region
private readonly MainPack _timeOutPack = new MainPack { Returncode = ReturnCode.MsgTimeOut };
private void CheckCsMsgTimeOut()
{
float nowTime = GameTime.time;
for (int i = 0; i < CHECK_TIMEOUT_PERFRAME; i++)
{
m_dwLastCheckIndex = (m_dwLastCheckIndex + 1) % MAX_MSG_HANDLE;
if (m_aMsgHandles[m_dwLastCheckIndex] != null)
{
if (m_fMsgRegTime[m_dwLastCheckIndex] + m_timeout < nowTime)
{
TLogger.LogError("msg timeout, resCmdID[{0}]", m_aMsgHandles[m_dwLastCheckIndex]);
NotifyTimeout(m_aMsgHandles[m_dwLastCheckIndex]);
RmvCheckCsMsg((int)m_dwLastCheckIndex);
}
}
}
}
public void RmvCheckCsMsg(int index)
{
m_aMsgHandles[index] = null;
m_fMsgRegTime[index] = 0;
}
private void RegTimeOutHandle(uint actionCode, CsMsgDelegate resHandler)
{
uint hashIndex = actionCode % MAX_MSG_HANDLE;
m_aMsgHandles[hashIndex] = resHandler;
m_fMsgRegTime[hashIndex] = GameTime.time;
}
protected void NotifyTimeout(CsMsgDelegate msgHandler)
{
msgHandler(_timeOutPack);
}
#endregion
private void HandleCsMsgOnUpdate()
{
if (cachelistHandle.Count <= 0 || queuepPacks.Count <= 0)
{
return;
}
try
{
foreach (CsMsgDelegate handle in cachelistHandle.Dequeue())
{
handle(queuepPacks.Peek());
}
queuepPacks.Dequeue();
}
catch (Exception e)
{
TLogger.LogError(e.Message);
}
}
protected override void Init()
{
base.Init();
}
public override void Active()
{
base.Active();
}
public override void Release()
{
base.Release();
}
public bool IsStatusCanSendMsg()
{
if (m_status == GameClientStatus.StatusEnter)
{
return true;
}
float nowTime = GameTime.time;
if (m_lastLogDisconnectErrTime + 5 < nowTime)
{
TLogger.LogError("GameClient not connected, send msg failed");
m_lastLogDisconnectErrTime = nowTime;
}
return false;
}
/// <summary>
/// 设置是否需要监控网络重连
/// </summary>
/// <param name="needWatch"></param>
public void SetWatchReconnect(bool needWatch)
{
m_connectWatcher.Enable = needWatch;
}
#region Ping
/// <summary>
/// ping值
/// </summary>
public int Ping
{
get
{
if (IsPingValid())
{
return m_ping / 4;
}
else
{
return 0;
}
}
}
public bool IsPingValid()
{
if (IsNetworkOkAndLogined)
{
return m_ping >= 0;
}
return false;
}
#endregion
#region GetNetworkType
public static CsNetworkType GetNetworkType()
{
CsNetworkType csNetType = CsNetworkType.CSNETWORK_UNKNOWN;
NetworkReachability reachability = Application.internetReachability;
switch (reachability)
{
case NetworkReachability.NotReachable:
break;
case NetworkReachability.ReachableViaLocalAreaNetwork:
csNetType = CsNetworkType.CSNETWORK_WIFI;
break;
case NetworkReachability.ReachableViaCarrierDataNetwork:
csNetType = CsNetworkType.CSNETWORK_3G;
break;
}
return csNetType;
}
public enum CsNetworkType
{
CSNETWORK_UNKNOWN = 0, /*未知类型*/
CSNETWORK_WIFI = 1, /*Wifi类型*/
CSNETWORK_3G = 2, /*3G类型*/
CSNETWORK_2G = 3 /*2G类型*/
};
#endregion
}
}

View File

@@ -0,0 +1,48 @@
namespace TEngineCore.Net
{
public interface IDataCenterModule
{
void Init();
void OnRoleLogout();
void OnUpdate();
void OnMainPlayerMapChange();
}
public class DataCenterModule<T> : IDataCenterModule where T : new()
{
private static T instance;
public static T Instance
{
get
{
if (null == instance)
{
instance = new T();
}
return instance;
}
}
public virtual void Init()
{
}
public virtual void OnRoleLogout()
{
}
public virtual void OnUpdate()
{
}
public virtual void OnMainPlayerMapChange()
{
}
}
}

View File

@@ -0,0 +1,9 @@
namespace TEngineCore.Net
{
internal class NetEventId
{
public static int HeartBeat = StringId.StringToHash("NetEventId.HeartBeat");
public static int ConnectTcp = StringId.StringToHash("NetEventId.ConnectTcp");
public static int ConnectUdp = StringId.StringToHash("NetEventId.ConnectUdp");
}
}

View File

@@ -0,0 +1,52 @@
using System.IO;
using JetBrains.Annotations;
namespace TEngineCore.Net
{
public class ProtoUtils
{
/// <summary>
/// 序列化 MainPack -> byte[]
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="mainPack"></param>
/// <returns></returns>
[CanBeNull]
public static byte[] Serialize<T>(T mainPack) where T : class
{
try
{
using (var stream = new System.IO.MemoryStream())
{
ProtoBuf.Serializer.Serialize(stream, mainPack);
return stream.ToArray();
}
}
catch (IOException ex)
{
TLogger.LogError($"[Serialize] Error{ex.Message}, {ex.Data["StackTrace"]}");
return null;
}
}
/// <summary>
/// 反序列化
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="buffer"></param>
/// <returns></returns>
[CanBeNull]
public static T DeSerialize<T>(byte[] buffer) where T : class
{
try
{
return ProtoBuf.Serializer.Deserialize(typeof(T), new System.IO.MemoryStream(buffer)) as T;
}
catch (IOException ex)
{
TLogger.LogError(($"[DeSerialize] 错误:{ex.Message}, {ex.Data["StackTrace"]}"));
return null;
}
}
}
}