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.
269 lines
7.3 KiB
269 lines
7.3 KiB
/*
|
|
Sog 游戏基础库
|
|
2016 by zouwei
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Sog
|
|
{
|
|
public delegate void OnClusterMessageHandler(uint remoteAppID, MessageData message);
|
|
|
|
public enum ServerStopStage
|
|
{
|
|
none = 0,
|
|
prepare = 1,
|
|
stopping = 2,
|
|
}
|
|
|
|
public class ServerApp
|
|
{
|
|
private bool m_bRunning;
|
|
|
|
private Cluster m_cluster;
|
|
|
|
private int m_iTickCountForSleep;
|
|
private int MaxTickCountNeedSleep = 1;
|
|
|
|
private int m_noTickCount;
|
|
public int ProcessMsgCountOnce = 100;
|
|
private long m_lastExceptionTime;
|
|
private int m_exceptionCount;
|
|
|
|
public long TotalTickCount { get; private set; } //服务器总共tick次数
|
|
|
|
public long ServerStartTime; //服务器开始运行的时间
|
|
|
|
//服务器id,也叫appid
|
|
public uint ServerID { get; private set; }
|
|
//字符串格式的serverid
|
|
public string StrServerID { get; private set; }
|
|
|
|
public AppParam AppParam { get; private set; }
|
|
|
|
public AppTime Time { get; }
|
|
|
|
public string ClusterName
|
|
{
|
|
get { return m_cluster.ClusterName; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 随机数
|
|
/// </summary>
|
|
public Random Rand { get; }
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public AppAlerter Alerter { get; }
|
|
|
|
public ServerStopStage CurrStopStage { get; private set; }
|
|
|
|
public delegate void OnInitHandler();
|
|
public delegate void OnStopHandler();
|
|
public delegate void OnReloadHandler();
|
|
public delegate void OnTickHandler(long nowMs);
|
|
|
|
|
|
public OnInitHandler OnInit;
|
|
public OnStopHandler OnStop;
|
|
public OnReloadHandler OnReload;
|
|
public OnTickHandler OnTick;
|
|
public OnClusterMessageHandler OnClusterMessage;
|
|
|
|
public ServerApp(AppParam appParam)
|
|
{
|
|
AppParam = appParam;
|
|
|
|
Time = new AppTime();
|
|
Time.UpdateTime();
|
|
Rand = new Random();
|
|
|
|
ServerID = AppParam.ServerID;
|
|
StrServerID = ServerIDUtils.IDToString(ServerID);
|
|
|
|
m_bRunning = false;
|
|
ServerStartTime = DateTimeOffset.Now.ToUnixTimeMilliseconds()/1000;
|
|
|
|
JsonConfig.InitLitJson();
|
|
|
|
m_cluster = new Cluster(this, ServerID);
|
|
Alerter = new AppAlerter(this);
|
|
CurrStopStage = ServerStopStage.none;
|
|
|
|
if(OSUtils.IsWindows())
|
|
{
|
|
MaxTickCountNeedSleep = 10;
|
|
}
|
|
|
|
//如果有cluster配置的话
|
|
if (AppParam.ClusterFileName != null)
|
|
{
|
|
m_cluster.InitAppByConfig(AppParam.ClusterFileName);
|
|
|
|
if (AppParam.ConfigFileName == null)
|
|
{
|
|
AppParam.ConfigFileName = m_cluster.GetAppConfigFile();
|
|
AppParam.LoadServerConfig();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public Cluster GetCluster()
|
|
{
|
|
return m_cluster;
|
|
}
|
|
|
|
public void Run()
|
|
{
|
|
//windows的sleep显然精度更低
|
|
//要符合要求,至少设置成10,但是windows反正不跑生产环境,这里设置成1就可以了,无所谓精度
|
|
//linux usleep的精度很高,先设置成1试试,最多2够了
|
|
//m_iIdleCountForSleep = OSUtils.IsWindows() ? 2 : 1;
|
|
//m_iIdleSleepMS = 1;
|
|
|
|
m_bRunning = true;
|
|
|
|
m_cluster.Start();
|
|
|
|
while (m_bRunning)
|
|
{
|
|
try
|
|
{
|
|
TotalTickCount++;
|
|
|
|
Time.UpdateTime();
|
|
|
|
//GCTest.Instance.TestMemoryNew();
|
|
|
|
long nowMs = Time.GetTime();
|
|
|
|
int iRecvMsgCount = m_cluster.Update(OnClusterMessage, ProcessMsgCountOnce, nowMs);
|
|
|
|
if(iRecvMsgCount >= ProcessMsgCountOnce)
|
|
{
|
|
m_noTickCount++;
|
|
//最多处理10次消息,如果消息还没处理完成,强制tick一次
|
|
if(m_noTickCount > 5)
|
|
{
|
|
m_noTickCount = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_noTickCount = 0;
|
|
}
|
|
|
|
if (m_noTickCount == 0)
|
|
{
|
|
if (OnTick != null)
|
|
{
|
|
m_iTickCountForSleep++;
|
|
|
|
GCMonitor.Instance.ScriptOnTick();
|
|
|
|
OnTick(nowMs);
|
|
}
|
|
|
|
// windows下sleep一下要10ms,linux虚拟机也快不到哪里去,所以不能sleep太多
|
|
if (m_iTickCountForSleep >= MaxTickCountNeedSleep)
|
|
{
|
|
m_iTickCountForSleep = 0;
|
|
System.Threading.Thread.Sleep(1);
|
|
}
|
|
|
|
}
|
|
|
|
GCMonitor.Instance.Tick();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
m_exceptionCount++;
|
|
|
|
long nowMs = Time.GetTime();
|
|
|
|
// 1秒只能抛出有限个异常,太多的直接忽略,免得影响服务器效率
|
|
if (nowMs - m_lastExceptionTime > 1000)
|
|
{
|
|
m_lastExceptionTime = nowMs;
|
|
m_exceptionCount = 0;
|
|
}
|
|
|
|
if (m_exceptionCount <= 1)
|
|
{
|
|
TraceLog.Exception(ex);
|
|
}
|
|
|
|
//windows下发现逻辑错误直接退出程序
|
|
if (OSUtils.IsWindows())
|
|
{
|
|
//等待写日志
|
|
System.Threading.Thread.Sleep(1000);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Alerter.AlertException(ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_cluster.Close();
|
|
}
|
|
|
|
public void RunInBackground()
|
|
{
|
|
System.Threading.Thread runTask = new System.Threading.Thread(this.Run);
|
|
runTask.Start();
|
|
}
|
|
|
|
public long GetTimeSecond()
|
|
{
|
|
return Time.GetTimeSecond();
|
|
}
|
|
|
|
public bool IsStopping => CurrStopStage != ServerStopStage.none;
|
|
public bool IsRunning()
|
|
{
|
|
return m_bRunning;
|
|
}
|
|
|
|
|
|
public void Exit()
|
|
{
|
|
TraceLog.Debug("ServerApp.Exit be call, exit server!");
|
|
|
|
m_bRunning = false;
|
|
}
|
|
|
|
public void PrepareStop()
|
|
{
|
|
if (CurrStopStage == ServerStopStage.none)
|
|
{
|
|
CurrStopStage = ServerStopStage.prepare;
|
|
}
|
|
}
|
|
|
|
public void StopServer()
|
|
{
|
|
CurrStopStage = ServerStopStage.stopping;
|
|
|
|
if (OnStop != null)
|
|
{
|
|
OnStop();
|
|
}
|
|
}
|
|
|
|
//逻辑服务器停服成功后调用,服务器将会退出
|
|
public void SetStopSuccess()
|
|
{
|
|
m_bRunning = false;
|
|
}
|
|
|
|
}
|
|
}
|
|
|