From 2a0543e79eb2207fe465b57b79136bb9a43a6368 Mon Sep 17 00:00:00 2001 From: xeon Date: Sat, 20 Jan 2024 01:39:12 +0300 Subject: [PATCH] Unregistering sessions properly, more logging, proper shutdown --- RPG.Network.Proto/server_only.proto | 1 + RPG.Services.Core/Network/ServiceEndPoint.cs | 10 +++---- RPG.Services.Core/Session/SessionManager.cs | 8 ++++- .../Command/GameserverCommandHandler.cs | 6 ++-- .../Command/GateserverCommandHandler.cs | 30 +++++++++++-------- .../Network/Tcp/TcpGateway.cs | 15 +++++++--- .../Session/NetworkSession.cs | 12 ++++++++ 7 files changed, 56 insertions(+), 26 deletions(-) diff --git a/RPG.Network.Proto/server_only.proto b/RPG.Network.Proto/server_only.proto index b48b344..ca6c727 100644 --- a/RPG.Network.Proto/server_only.proto +++ b/RPG.Network.Proto/server_only.proto @@ -28,6 +28,7 @@ message CmdBindContainerResult { uint32 retcode = 1; uint64 session_id = 2; + RPGServiceType service_type = 3; } message CmdUnbindContainer diff --git a/RPG.Services.Core/Network/ServiceEndPoint.cs b/RPG.Services.Core/Network/ServiceEndPoint.cs index 52d9ed7..caba581 100644 --- a/RPG.Services.Core/Network/ServiceEndPoint.cs +++ b/RPG.Services.Core/Network/ServiceEndPoint.cs @@ -9,7 +9,6 @@ internal class ServiceEndPoint private readonly NetMQSocket _socket; private CancellationTokenSource? _receiveCancellation; - private Task? _receiveTask; public delegate Task CommandEventHandler(ServiceCommand command); public event CommandEventHandler? OnCommand; @@ -23,7 +22,7 @@ internal class ServiceEndPoint public void Start() { _receiveCancellation = new(); - _receiveTask = Task.Run(() => Receive(_receiveCancellation.Token)); + _ = Task.Run(() => Receive(_receiveCancellation.Token)); } private async Task Receive(CancellationToken cancellationToken) @@ -41,18 +40,17 @@ internal class ServiceEndPoint } } } - catch (Exception exception) when (exception is not OperationCanceledException) + catch { - throw; + if (!_socket.IsDisposed) _socket.Close(); } } public async Task StopAsync() { - if (_receiveCancellation != null && _receiveTask != null) + if (_receiveCancellation != null) { await _receiveCancellation.CancelAsync(); - await _receiveTask; } } } diff --git a/RPG.Services.Core/Session/SessionManager.cs b/RPG.Services.Core/Session/SessionManager.cs index f7d0c1c..5339c79 100644 --- a/RPG.Services.Core/Session/SessionManager.cs +++ b/RPG.Services.Core/Session/SessionManager.cs @@ -1,17 +1,20 @@ using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace RPG.Services.Core.Session; public class SessionManager { private readonly ConcurrentDictionary _sessions; private readonly IServiceProvider _serviceProvider; + private readonly ILogger _logger; - public SessionManager(IServiceProvider serviceProvider) + public SessionManager(IServiceProvider serviceProvider, ILogger logger) { _sessions = []; _serviceProvider = serviceProvider; + _logger = logger; } public TSession? Create(ulong id) where TSession : RPGSession @@ -21,6 +24,8 @@ public class SessionManager TSession session = ActivatorUtilities.CreateInstance(_serviceProvider, id); _sessions[id] = session; + _logger.LogInformation("New session (id={id}) registered", id); + return session; } @@ -41,6 +46,7 @@ public class SessionManager if (_sessions.TryRemove(session.SessionId, out _)) { session.Dispose(); + _logger.LogInformation("Session with id {id} was unregistered", session.SessionId); } } } diff --git a/RPG.Services.Gameserver/Network/Command/GameserverCommandHandler.cs b/RPG.Services.Gameserver/Network/Command/GameserverCommandHandler.cs index 2a37637..85242b9 100644 --- a/RPG.Services.Gameserver/Network/Command/GameserverCommandHandler.cs +++ b/RPG.Services.Gameserver/Network/Command/GameserverCommandHandler.cs @@ -26,7 +26,8 @@ internal class GameserverCommandHandler : ServiceCommandHandler Send(ServiceCommandType.BindContainerResult, new CmdBindContainerResult { Retcode = 1, - SessionId = cmdBindContainer.SessionId + SessionId = cmdBindContainer.SessionId, + ServiceType = RPGServiceType.Gameserver }, command.SenderType); return Task.CompletedTask; } @@ -35,7 +36,8 @@ internal class GameserverCommandHandler : ServiceCommandHandler Send(ServiceCommandType.BindContainerResult, new CmdBindContainerResult { Retcode = 0, - SessionId = cmdBindContainer.SessionId + SessionId = cmdBindContainer.SessionId, + ServiceType = RPGServiceType.Gameserver }, command.SenderType); return Task.CompletedTask; diff --git a/RPG.Services.Gateserver/Network/Command/GateserverCommandHandler.cs b/RPG.Services.Gateserver/Network/Command/GateserverCommandHandler.cs index 6c32141..8e4a01b 100644 --- a/RPG.Services.Gateserver/Network/Command/GateserverCommandHandler.cs +++ b/RPG.Services.Gateserver/Network/Command/GateserverCommandHandler.cs @@ -23,22 +23,26 @@ internal class GateserverCommandHandler : ServiceCommandHandler if (_sessionManager.TryGet(result.SessionId, out NetworkSession? session)) { - PlayerGetTokenScRsp rsp; - if (result.Retcode != 0) + session.ServiceBound(result.ServiceType); + if (result.ServiceType == RPGServiceType.Gameserver) { - rsp = new() { Retcode = 1 }; - } - else - { - rsp = new() + PlayerGetTokenScRsp rsp; + if (result.Retcode != 0) { - Retcode = 0, - Msg = "OK", - Uid = session.PlayerUid - }; - } + rsp = new() { Retcode = 1 }; + } + else + { + rsp = new() + { + Retcode = 0, + Msg = "OK", + Uid = session.PlayerUid + }; + } - await session.SendAsync((ushort)CmdType.CmdPlayerGetTokenScRsp, rsp); + await session.SendAsync((ushort)CmdType.CmdPlayerGetTokenScRsp, rsp); + } } } diff --git a/RPG.Services.Gateserver/Network/Tcp/TcpGateway.cs b/RPG.Services.Gateserver/Network/Tcp/TcpGateway.cs index 1cd99da..0b68fcd 100644 --- a/RPG.Services.Gateserver/Network/Tcp/TcpGateway.cs +++ b/RPG.Services.Gateserver/Network/Tcp/TcpGateway.cs @@ -59,6 +59,8 @@ internal class TcpGateway while (!cancellationToken.IsCancellationRequested) { Socket clientSocket = await _socket!.AcceptAsync(cancellationToken); + + _logger.LogInformation("New TCP connection from {remoteEndPoint}", clientSocket.RemoteEndPoint); _ = RunSessionAsync(clientSocket); } } @@ -66,22 +68,27 @@ internal class TcpGateway { throw; } + catch { /* Operation canceled */ } } private async Task RunSessionAsync(Socket socket) { + NetworkSession? session = _sessionManager.Create(Interlocked.Increment(ref _sessionIdCounter)); + if (session == null) return; + try { - NetworkSession? session = _sessionManager.Create(Interlocked.Increment(ref _sessionIdCounter)); - if (session == null) return; - session.Socket = socket; - await session.RunAsync(); } catch (Exception exception) when (exception is not OperationCanceledException) { _logger.LogError("Unhandled exception occurred: {exception}", exception); } + catch { /* Operation canceled */ } + finally + { + _sessionManager.Remove(session); + } } } diff --git a/RPG.Services.Gateserver/Session/NetworkSession.cs b/RPG.Services.Gateserver/Session/NetworkSession.cs index d167ee6..dd0bc92 100644 --- a/RPG.Services.Gateserver/Session/NetworkSession.cs +++ b/RPG.Services.Gateserver/Session/NetworkSession.cs @@ -12,12 +12,14 @@ internal class NetworkSession : RPGSession private const int ReceiveBufferSize = 16384; private readonly byte[] _recvBuffer; + private readonly List _boundServices; public Socket? Socket { private get; set; } public PlayerGetTokenCsReq? GetTokenCsReq { get; private set; } public NetworkSession(ulong sessionId, ServiceBox serviceBox) : base(sessionId, serviceBox) { + _boundServices = []; _recvBuffer = GC.AllocateUninitializedArray(ReceiveBufferSize); } @@ -48,6 +50,11 @@ internal class NetworkSession : RPGSession } } + public void ServiceBound(RPGServiceType serviceType) + { + _boundServices.Add(serviceType); + } + public async Task SendAsync(ushort cmdType, TBody body) where TBody : IMessage { await SendAsync(new(cmdType, ReadOnlyMemory.Empty, body.ToByteArray())); @@ -105,5 +112,10 @@ internal class NetworkSession : RPGSession public override void Dispose() { Socket?.Close(); + + foreach (RPGServiceType serviceType in _boundServices) + { + UnbindService(serviceType); + } } }