6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) + game logic (GameFix/GameDAL/ServerData) + network layer (NetWorkMessage) + data layer (ObjectModel) + utilities (MrWu/Core/Config/CloudAPI/dll) + adapters (zyxAdapter/base) .NET 8.0 C# solution, 16 projects, 958 source files
262 lines
8.1 KiB
C#
262 lines
8.1 KiB
C#
using System;
|
||
using MrWu.Debug;
|
||
using Server;
|
||
using WebSocketSharp.Server;
|
||
using System.Collections.Concurrent;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using GameMessage;
|
||
using MessagePack;
|
||
using MrWu;
|
||
using Server.Core;
|
||
|
||
namespace Server.Net
|
||
{
|
||
public class GameNetManager : SingleInstance<GameNetManager>, IDisposable
|
||
{
|
||
public static bool IsStart
|
||
{
|
||
get;
|
||
private set;
|
||
}
|
||
|
||
public bool IsDispose { get; private set; }
|
||
|
||
private WebSocketServer _webSocketServer;
|
||
|
||
/// <summary>
|
||
/// 会话集合
|
||
/// </summary>
|
||
private ConcurrentDictionary<long, Session> sessionDic = new ConcurrentDictionary<long, Session>();
|
||
|
||
/// <summary>
|
||
/// SessionIds 队列
|
||
/// </summary>
|
||
private readonly ConcurrentQueue<long> sessionIds = new ConcurrentQueue<long>();
|
||
|
||
/// <summary>
|
||
/// 当前的链接数
|
||
/// </summary>
|
||
public int ConnectCount
|
||
{
|
||
get { return sessionDic.Count; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前接收的数量
|
||
/// </summary>
|
||
public long ReceiveCount;
|
||
|
||
public const int MaxMessageSize = 1024 * 1024;
|
||
|
||
public event Action<Session> ConnectedEvt;
|
||
|
||
public event Action<Session> DisConnectedEvt;
|
||
|
||
public event Action<Session, byte[]> ReceiveEvt;
|
||
|
||
/// <summary>
|
||
/// 启动网络
|
||
/// </summary>
|
||
public void Start(string webPath, int webPort)
|
||
{
|
||
if (!string.IsNullOrEmpty(webPath) && webPort > 0)
|
||
{
|
||
//webSocket 服务 启动
|
||
GameWChannel.OnConnectedEvt += WConnected;
|
||
GameWChannel.OnDisconnectedEvt += WDisconnected;
|
||
GameWChannel.OnReceivedEvt += WReceived;
|
||
GameWChannel.OnErrorEvt += WError;
|
||
_webSocketServer = new WebSocketServer(webPort);
|
||
_webSocketServer.AddWebSocketService<GameWChannel>(webPath);
|
||
_webSocketServer.Start();
|
||
//webSocket 服务 结束
|
||
|
||
IsStart = true;
|
||
SessionUUIDManager.Instance.Init();
|
||
}
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
IsDispose = true;
|
||
WebSocketStop();
|
||
}
|
||
|
||
private void WebSocketStop()
|
||
{
|
||
Task.Factory.StartNew(() => { _webSocketServer?.Stop(); });
|
||
}
|
||
|
||
#region WebSocket 事件
|
||
|
||
private void WConnected(GameWChannel channel)
|
||
{
|
||
Session session = new Session(channel);
|
||
Interlocked.Exchange(ref session.ReadWriteTime, TimeInfo.Instance.FrameTime);
|
||
long id = session.Id;
|
||
channel.SessionId = id;
|
||
if (!sessionDic.TryAdd(id, session))
|
||
{
|
||
Debug.Error("添加 webSocket 链接到 字典失败!!!");
|
||
}
|
||
else
|
||
{
|
||
sessionIds.Enqueue(id);
|
||
try
|
||
{
|
||
ConnectedEvt?.Invoke(session);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.Error($"链接成功事件执行报错:{e.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void WDisconnected(GameWChannel channel)
|
||
{
|
||
long sessionId = channel.SessionId;
|
||
if (sessionDic.TryRemove(sessionId, out Session session))
|
||
{
|
||
lock (session.DisConnectLock)
|
||
{
|
||
try
|
||
{
|
||
DisConnectedEvt?.Invoke(session);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.Error($"断开连接事件执行报错:{e.Message}");
|
||
}
|
||
|
||
session.OnDisConnected();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!_forceDisConnectedSessionIds.TryRemove(sessionId, out Session _))
|
||
{
|
||
Debug.Error("webSocket断开连接,竟然未找到 session");
|
||
}
|
||
}
|
||
}
|
||
|
||
private ConcurrentDictionary<long,Session> _forceDisConnectedSessionIds = new ConcurrentDictionary<long, Session>();
|
||
|
||
public void ForceDisconnected(long sessionId)
|
||
{
|
||
if (sessionDic.TryRemove(sessionId, out Session session))
|
||
{
|
||
if (!_forceDisConnectedSessionIds.TryAdd(sessionId, session))
|
||
{
|
||
Debug.Error("不存在说添加不进去吧???");
|
||
}
|
||
|
||
lock (session.DisConnectLock)
|
||
{
|
||
try
|
||
{
|
||
DisConnectedEvt?.Invoke(session);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.Error($"断开连接事件执行报错:{e.Message}");
|
||
}
|
||
|
||
session.OnDisConnected();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.Error($"ForceDisconnected 断开连接,竟然未找到 session {sessionId}");
|
||
}
|
||
}
|
||
|
||
private void WReceived(GameWChannel channel, byte[] data)
|
||
{
|
||
long sessionId = channel.SessionId;
|
||
if (sessionDic.TryGetValue(sessionId, out Session session))
|
||
{
|
||
//因为没去掉头
|
||
Received(session, data, 0);
|
||
}
|
||
else
|
||
{
|
||
Debug.Error("接收到webSocket包,未找到会话!");
|
||
}
|
||
}
|
||
|
||
private void WError(GameWChannel channel, Exception e)
|
||
{
|
||
if (e == null)
|
||
{
|
||
Debug.Error($"Web Socket Error: e is null!");
|
||
}else
|
||
Debug.Error("Web Socket Error:" + e.Message);
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 接受到数据
|
||
/// </summary>
|
||
/// <param name="session"></param>
|
||
/// <param name="data"></param>
|
||
/// <param name="offset"></param>
|
||
private void Received(Session session, byte[] data, int offset)
|
||
{
|
||
try
|
||
{
|
||
ReceiveEvt?.Invoke(session, data);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.Error($"收包解析报错:{e.Message}");
|
||
}
|
||
}
|
||
|
||
public void Update()
|
||
{
|
||
// 清理超时,和失效的链接
|
||
long timeNow = TimeInfo.Instance.FrameTime;
|
||
const int MaxCheckNum = 10;
|
||
int n = this.sessionIds.Count;
|
||
if (n > MaxCheckNum)
|
||
{
|
||
n = MaxCheckNum;
|
||
}
|
||
|
||
for (int i = 0; i < n; i++)
|
||
{
|
||
if (this.sessionIds.TryDequeue(out long sessionId))
|
||
{
|
||
if (this.sessionDic.TryGetValue(sessionId, out Session session))
|
||
{
|
||
if (timeNow - session.ReadWriteTime > 20 * 1000)
|
||
{
|
||
Debug.Info($"超时断线! {session.IsDisConnected}");
|
||
//var key = Debug.StartTiming();
|
||
session.DisConnected();
|
||
// double runtime = Debug.GetRunTime(key);
|
||
// if (runtime > 20)
|
||
// {
|
||
// Debug.Warning($"NetManager runtime:{runtime},n:{n}");
|
||
// }
|
||
//超时断线
|
||
continue;
|
||
}
|
||
|
||
this.sessionIds.Enqueue(sessionId);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |