Files
hjha-server/GameNetModule/GameNet/Base/GameNetManager.cs
xiaoou e9616125ce feat: initial commit - HJHA game server full source
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
2026-07-07 12:02:15 +08:00

262 lines
8.1 KiB
C#
Raw 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 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;
}
}
}
}
}