using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Diagnostics; using Google.Protobuf; using Nettention.Proud; using OtpNet; using ServerCore; using ServerBase; using MODULE_ID = System.UInt32; using HostID = Nettention.Proud.HostID; using SESSION_ID = System.Int32; namespace ServerBase; //============================================================================================= // 네트워크 세션 기반 클래스 이다. // // author : kangms // //============================================================================================= public abstract partial class SessionBase : ISession, IInitializer { private readonly IRmiHost m_net_host; private ConcurrentDictionary m_stubs = new(); private ConcurrentDictionary m_proxies = new(); public delegate bool onRecv(Nettention.Proud.HostID remote, Nettention.Proud.RmiContext rmiContext, T recvProtocol); public delegate bool FnProudNetIOPacketToHost(Nettention.Proud.HostID remote, Nettention.Proud.RmiContext rmiContext, IMessage msg); public FnProudNetIOPacketToHost? FnSendPacketToHost; public delegate bool FnProudNetIOPacketToHosts(Nettention.Proud.HostID[] remotes, Nettention.Proud.RmiContext rmiContext, IMessage msg); public FnProudNetIOPacketToHosts? FnSendPacketToHosts; private readonly PacketReceiver m_packet_receiver; private readonly PacketSender m_packet_sender; private int m_large_packet_check_size = Constant.LARGE_PACKET_CHECK_DEFAULT_SIZE; private int m_packet_chunk_size = Constant.PACKET_CHUNK_DEFAULT_SIZE; private LargePacketHandler m_large_packet_handler = new(); public enum ConnectionState { None = 0, Disconnected = 1, TryConnecting = 2, Connected = 3, } private ConnectionState m_connection_state = ConnectionState.Disconnected; public SessionBase(IRmiHost rmiHost) { m_net_host = rmiHost; m_packet_receiver = new PacketReceiver(this); m_packet_sender = new PacketSender(this); } // for IInitializer public virtual async Task onInit() { var result = new Result(); string err_msg = string.Empty; var rmi_host = getRmiHost(); if(null == rmi_host) { err_msg = $"Rmi Host is Null !!! - {toBasicString()}"; result.setFail(ServerErrorCode.RmiHostIsNull, err_msg); Log.getLogger().error(result.toBasicString()); return result; } if(false == onBindRmiHostHandler(rmi_host)) { err_msg = $"Failed to bind Rmi Host Handler !!! - {toBasicString()}"; result.setFail(ServerErrorCode.RmiHostHandlerBindFailed, err_msg); Log.getLogger().error(result.toBasicString()); return result; } if (false == await m_packet_receiver.registerRecvHandlerAll()) { err_msg = $"Failed to register RecvHandler All !!! - {toBasicString()}"; result.setFail(ServerErrorCode.PacketRecvHandlerRegisterFailed, err_msg); Log.getLogger().error(result.toBasicString()); return result; } if (false == await m_packet_sender.registerSendHandlerAll()) { err_msg = $"Failed to register SendHandler All !!! - {toBasicString()}"; result.setFail(ServerErrorCode.PacketSendHandlerRegisterFailed, err_msg); Log.getLogger().error(result.toBasicString()); return result; } if (false == await m_packet_receiver.registerP2PRecvHandlerAll()) { //P2PPacketRecvHandler 여러개 추가 할시 Result 필요 var msg = $"Failed to register P2P RecvHandler All !!! - {toBasicString()}"; //result.setFail(ServerErrorCode.PacketRecvHandlerRegisterFailed, err_msg); Log.getLogger().warn(msg); } return result; } public bool resisterStub(TStub stub) where TStub : Nettention.Proud.RmiStub { var net_server = getRmiHost(); NullReferenceCheckHelper.throwIfNull(net_server, () => $"net_server is null !!!"); if (false == m_stubs.TryAdd(typeof(TStub), stub)) { return false; } net_server.AttachStub(stub); return true; } public bool unresisterStub(Type type) { return m_stubs.TryRemove(type, out _); } public TStub findStub() where TStub : Nettention.Proud.RmiStub { m_stubs.TryGetValue(typeof(TStub), out var found_stub); var casted_stub = found_stub as TStub; NullReferenceCheckHelper.throwIfNull(casted_stub, () => $"casted_stub is null !!! : type:{typeof(TStub).getTypeName()}"); return casted_stub; } public bool resisterProxy(TProxy proxy) where TProxy : Nettention.Proud.RmiProxy { var net_server = getRmiHost(); NullReferenceCheckHelper.throwIfNull(net_server, () => $"net_server is null !!!"); if(false == m_proxies.TryAdd(typeof(TProxy), proxy)) { return false; } net_server.AttachProxy(proxy); return true; } public bool unresisterProxy(Type type) { return m_proxies.TryRemove(type, out _); } public TProxy findProxy() where TProxy : Nettention.Proud.RmiProxy { m_proxies.TryGetValue(typeof(TProxy), out var found_proxy); var casted_proxy = found_proxy as TProxy; NullReferenceCheckHelper.throwIfNull(casted_proxy, () => $"casted_proxy is null !!! : type:{typeof(TProxy).getTypeName()}"); return casted_proxy; } #region 재정의 해야 하는 함수들 protected abstract bool onBindRmiHostHandler(IRmiHost currRmiHost); protected abstract bool onBindStubHandler(); #endregion 재정의 해야 하는 함수들 public abstract IEntityWithSession? onLookupEntityWithSession(SESSION_ID targetSessionId); protected bool onRecvProtocol(Nettention.Proud.HostID remote, Nettention.Proud.RmiContext rmiContext, T recvProtocol) where T : Google.Protobuf.IMessage { var err_msg = string.Empty; var session_id = 0; var recv_protocol_type = string.Empty; var entity_basic_string = string.Empty; try { ArgumentNullReferenceCheckHelper.throwIfNull(rmiContext, () => $"rmiContext is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(recvProtocol, () => $"recvProtocol is null !!!"); Log.getLogger().debug($"recvProtocol:{recvProtocol.ToString()} - HostID:{remote}"); session_id = remote.toSESSION_ID(); recv_protocol_type = recvProtocol.ToString(); var found_entity_with_session = onLookupEntityWithSession(session_id); if (found_entity_with_session == null) { err_msg = $"Not found remoteSession !!! - sessionId:{session_id}, recvProtocolType:{recv_protocol_type}, HostID:{remote}"; Log.getLogger().warn(err_msg); return false; } entity_basic_string = found_entity_with_session.toBasicString(); Log.getLogger().debug($"recvByEntitySession:{recvProtocol.ToString()} - {entity_basic_string}"); var task_serializer = found_entity_with_session as IWithTaskSerializer; if (null == task_serializer) { err_msg = $"Failed to cast IWithTaskSerializer - sessionId:{session_id}, recvProtocolType:{recv_protocol_type}, HostID:{remote}, entityBasicString:{entity_basic_string}"; Log.getLogger().error(err_msg); return false; } recvProtocol.makeProudNetPacketCommand(out var packetCommand); NullReferenceCheckHelper.throwIfNull(packetCommand, () => $"packetCommand is null !!! - entityBasicString:{entity_basic_string}"); var func = getCallProtocolHandler(found_entity_with_session, recvProtocol, packetCommand); _ = task_serializer.getTaskSerializer().postLogicFunc(func, packetCommand.toBasicString()); } catch(Exception e) { Log.getLogger().fatal($"Exception !!!, Failed to perform in SessionBase.onRecvProtocol<{recvProtocol.getTypeName()}>() : exception:{e} - sessionId:{session_id}, recvProtocolType:{recv_protocol_type}, HostID:{remote}, entityBasicString:{entity_basic_string}"); return false; } return true; } public Func getCallProtocolHandler(IEntityWithSession session, T recvProtocol, ProudNetPacketCommand packetCommand) where T : Google.Protobuf.IMessage { ArgumentNullReferenceCheckHelper.throwIfNull(session, () => $"Session is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(recvProtocol, () => $"recvProtocol is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(packetCommand, () => $"packetCommand is null !!!"); System.Type command_type = packetCommand.getCommandType(); switch (command_type) { case var _ when command_type == typeof(ClientToGameReq.Types.C2S_REQ_LARGE_PACKET): return async () => await onCallLargeSizeProtocolHandler(session, recvProtocol); default: return async () => await onCallProtocolHandler(session, recvProtocol); } } public async Task onCallProtocolHandler(IEntityWithSession session, T recvProtocol) where T : Google.Protobuf.IMessage { var result = new Result(); var err_msg = string.Empty; ProudNetPacketCommand? fillup_packet_command = null; PacketRecvHandler? found_recv_packet_handler = null; try { ArgumentNullReferenceCheckHelper.throwIfNull(session, () => $"session is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(recvProtocol, () => $"recvProtocol is null !!! - {session.toBasicString()}"); Stopwatch? stopwatch = null; var event_tid = string.Empty; var server_logic = ServerLogicApp.getServerLogicApp(); NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {session.toBasicString()}"); var config = server_logic.getServerConfig(); NullReferenceCheckHelper.throwIfNull(config, () => $"config is null !!! - {session.toBasicString()}"); if (true == config.PerformanceCheckEnable) { event_tid = System.Guid.NewGuid().ToString("N"); stopwatch = Stopwatch.StartNew(); } var receiver = getPacketReceiver(); NullReferenceCheckHelper.throwIfNull(receiver, fnLog: () => $"receiver is null !!! - {session.toBasicString()}"); if (false == receiver.fillupProudNetPacketCommand(recvProtocol, out fillup_packet_command)) { err_msg = $"Failed to PacketReceiver.fillupProudNetPacketCommand() !!! : {recvProtocol.ToString()} - {session.toBasicString()}"; result.setFail(ServerErrorCode.PacketRecvInvalid, err_msg); Log.getLogger().error(result.toBasicString()); return result; } NullReferenceCheckHelper.throwIfNull(fillup_packet_command, fnLog: () => $"fillup_packet_command is null !!! - {session.toBasicString()}"); found_recv_packet_handler = receiver.findRecvHandler(fillup_packet_command); if (null == found_recv_packet_handler) { err_msg = $"Not found Recv Packet Handler !!! : {recvProtocol.ToString()} - {session.toBasicString()}"; result.setFail(ServerErrorCode.RacketRecvHandlerNotFound, err_msg); Log.getLogger().error(result.toBasicString()); return result; } result = await found_recv_packet_handler.onCheckValid(session, recvProtocol); if (result.isFail()) { Log.getLogger().error($"Failed to onCheckValid() !!! : {result.toBasicString()} - {fillup_packet_command.toBasicString()}"); return result; } result = await found_recv_packet_handler.onProcessPacket(session, recvProtocol); if (result.isFail()) { Log.getLogger().error($"Failed to onProcessPacket() !!! : {result.toBasicString()} - {fillup_packet_command.toBasicString()}"); } if (null != stopwatch) { var elapsed_msec = stopwatch.ElapsedMilliseconds; stopwatch.Stop(); Log.getLogger().debug($"{GetType()} CSPacket Stopwatch Stop : ETID:{event_tid}, ElapsedMSec:{elapsed_msec} - {recvProtocol.toBasicString()}"); } } catch(Exception e) { try { err_msg = $"Exception !!!, Failed to perform in SessionBase.onCallProtocolHandler() !!! : exception:{e} - PacketCommand:{fillup_packet_command?.toBasicString()}, {session?.toBasicString()}"; result.setFail(ServerErrorCode.TryCatchException, err_msg); Log.getLogger().error(result.toBasicString()); if (null != found_recv_packet_handler && null != session) { await found_recv_packet_handler.onProcessPacketException(session, recvProtocol, result); } } catch(Exception innerException) { err_msg = $"InnerException !!!, Failed to perform in SessionBase.onCallProtocolHandler() !!! : exception:{innerException}"; result.setFail(ServerErrorCode.TryCatchException, err_msg); Log.getLogger().error(result.toBasicString()); } } return result; } public async Task onCallLargeSizeProtocolHandler(IEntityWithSession session, T recvProtocol) where T : Google.Protobuf.IMessage { await Task.CompletedTask; var result = new Result(); var err_msg = string.Empty; try { var network_session = m_large_packet_handler.getNetworkSession(); NullReferenceCheckHelper.throwIfNull(network_session, () => $"network_session is null !!! - {session.toBasicString()}"); ArgumentNullReferenceCheckHelper.throwIfNull(session, fnLog: () => $"session is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(recvProtocol, fnLog: () => $"recvProtocol is null !!! - {session.toBasicString()}"); var recv_msg = recvProtocol as ClientToGame; NullReferenceCheckHelper.throwIfNull(recv_msg, fnLog: () => $"recv_msg is null !!! - {session.toBasicString()}"); var request = recv_msg.Request.ReqLargePacket; NullReferenceCheckHelper.throwIfNull(request, fnLog: () => $"request is null !!! - {session.toBasicString()}"); string packet_uid = request.Uid; Int32 packet_index = request.PacketIndex; Int32 total_packet_count = request.TotalPacketCount; m_large_packet_handler.collectPacket(session, packet_uid, total_packet_count, packet_index, request.Data); } catch(Exception e) { var error_coce = ServerErrorCode.TryCatchException; err_msg = $"Exception !!!, Failed to perform in onCallLargeSizeProtocolHandler() !!! : errorCode:{error_coce}, exception:{e} - PacketCommand:{recvProtocol?.toBasicString()}, {session?.toBasicString()}"; result.setFail(error_coce, err_msg); Log.getLogger().error(result.toBasicString()); } return result; } #region 패킷 송신용 함수들 public bool onSendPacket(IEntityWithSession session, T msg) where T : class, IMessage { return sendPacket(session, msg, RmiContext.ReliableSend); } public bool onSendPacket(IEntityWithSession[] sessions, T msg) where T : class, IMessage { return sendPacket(sessions, msg, ServerCore.ProudNetHelper.compressRmi()); } public bool onSendPacketWithSecure(IEntityWithSession session, T msg) where T : class, IMessage { return sendPacket(session, msg, RmiContext.SecureReliableSend); } public bool onSendPacketWithSecure(IEntityWithSession[] sessions, T msg) where T : class, IMessage { return sendPacket(sessions, msg, RmiContext.SecureReliableSend); } private bool sendPacket(IEntityWithSession session, T msg, RmiContext rmiContext) where T : class, IMessage { ArgumentNullReferenceCheckHelper.throwIfNull(session, () => $"session is null !!!"); var host_id = session.getHostId(); var base_msg = msg as IMessage; ArgumentNullReferenceCheckHelper.throwIfNull(base_msg, () => $"base_msg is null !!! - {session.toBasicString()}"); var msg_size = base_msg.CalculateSize(); var to_send_msgs = checkSizeAndConvertMessage(msg, msg_size); foreach (var to_send_msg in to_send_msgs) { var send_msg = to_send_msg as IMessage; NullReferenceCheckHelper.throwIfNull(send_msg, () => $"send_msg is null !!! - {session.toBasicString()}"); var send_msg_size = send_msg.CalculateSize(); string send_message = send_msg.ToString() ?? string.Empty; var err_msg = $"{toTrySendString(host_id, send_message, send_msg_size)} - {session.toBasicString()}"; Log.getLogger().debug(err_msg); var is_success = FnSendPacketToHost?.Invoke(host_id, rmiContext, send_msg); if (false == is_success) { err_msg = $"{toFailedSendString(host_id, send_message, msg_size)} - {session.toBasicString()}"; Log.getLogger().error(err_msg); } } return true; } private bool sendPacket(IEntityWithSession[] sessions, T msg, RmiContext rmiContext) where T : class, IMessage { ArgumentNullReferenceCheckHelper.throwIfNull(sessions, () => $"sessions is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(rmiContext, () => $"rmiContext is null !!!"); var host_ids = new Nettention.Proud.HostID[sessions.Length]; for(var i = 0; i < host_ids.Length; i++) { host_ids[i] = sessions[i].getHostId(); } var base_msg = msg as IMessage; NullReferenceCheckHelper.throwIfNull(base_msg, () => $"base_msg is null !!! - {toBasicString()}"); var msg_size = base_msg.CalculateSize(); var to_send_msgs = checkSizeAndConvertMessage(msg, msg_size); foreach (var to_send_msg in to_send_msgs) { var send_msg = to_send_msg as IMessage; NullReferenceCheckHelper.throwIfNull(send_msg, () => $"send_msg is null !!! - {toBasicString()}"); var send_msg_size = send_msg.CalculateSize(); string send_message = send_msg.ToString() ?? string.Empty; var err_msg = $"{toTrySendStrings(host_ids, send_message, send_msg_size)}"; Log.getLogger().debug(err_msg); var is_success = FnSendPacketToHosts?.Invoke(host_ids, rmiContext, send_msg); if (false == is_success) { err_msg = $"{toFailedSendStrings(host_ids, send_message, msg_size)}"; Log.getLogger().error(err_msg); } } return true; } private List checkSizeAndConvertMessage(T msg, int msg_size) where T : class, IMessage { var msgs = new List(); if (false == Constant.IS_LARGE_PACKET_PROTOCOL_ACTIVE) { msgs.Add(msg); return msgs; } if (msg_size > getLargePacketCheckSize()) { var byte_string = msg.ToByteString(); byte[] byteArray = byte_string.ToByteArray(); int chunkSize = getPacketChunkSize(); int numberOfChunks = (int)Math.Ceiling((double)byteArray.Length / chunkSize); var uid = KeyGeneration.GenerateRandomKey(20); var otp_encoding_by_base32 = Base32Encoding.ToString(uid); for (int i = 0; i < numberOfChunks; i++) { int startIndex = i * chunkSize; int length = Math.Min(chunkSize, byteArray.Length - startIndex); byte[] chunk = new byte[length]; Array.Copy(byteArray, startIndex, chunk, 0, length); ByteString chunkByteString = ByteString.CopyFrom(chunk); var cToG = new ClientToGame(); cToG.Response = new(); cToG.Response.AckLargePacket = new(); cToG.Response.AckLargePacket.PacketIndex = i; cToG.Response.AckLargePacket.Uid = otp_encoding_by_base32; cToG.Response.AckLargePacket.Data = chunkByteString; cToG.Response.AckLargePacket.TotalPacketCount = numberOfChunks; var chunk_msg = cToG as IMessage; msgs.Add((T)chunk_msg); } } else { msgs.Add(msg); } return msgs; } protected bool onRecvP2PMotionSync(Nettention.Proud.HostID remote,Nettention.Proud.RmiContext rmiContext, System.String id, Nettention.Proud.ByteArray data) { var session_id = remote.toSESSION_ID(); var found_entity_with_session = onLookupEntityWithSession(session_id); if (found_entity_with_session == null) { //err_msg = $"Not found remoteSession !!! - sessionId:{session_id}, recvProtocolType:{recv_protocol_type}, HostID:{remote}"; //Log.getLogger().warn(err_msg); return false; } PacketReceiver receiver = getPacketReceiver(); NullReferenceCheckHelper.throwIfNull(receiver, fnLog: () => $"receiver is null !!! - {found_entity_with_session.toBasicString()}"); var p2p_recv_handler = receiver.findP2PPacketHandler(""); if (null == p2p_recv_handler) { var err_msg = $"Not found Recv Packet Handler !!! : {found_entity_with_session.toBasicString()}"; Log.getLogger().error(err_msg); return false; } p2p_recv_handler.onProcessP2PPacket(found_entity_with_session, data); return true; } #endregion 패킷 송신용 함수들 #region 로그용 문자열 함수들 public abstract string toBasicString(); public virtual string toTrySendString(Nettention.Proud.HostID hostId, string msgType, Int32 length) => $"Packet Try Send2Net - TargetHostId:{hostId}, msgType:{msgType}, length:{length}"; public virtual string toFailedSendString(Nettention.Proud.HostID hostId, string msgType, Int32 length) => $"Packet Failed !!! Send2Net - TargetHostId:{hostId}, msgType:{msgType}, length:{length}"; public virtual string toTrySendStrings(Nettention.Proud.HostID[] hostIds, string msgType, Int32 length) => $"Packet Try Send2Net - TargetHostIds:{hostIds}..., msgType:{msgType}, length:{length}"; public virtual string toFailedSendStrings(Nettention.Proud.HostID[] hostIds, string msgType, Int32 length) => $"Packet Failed !!! Send2Net - TargetHostIds:{hostIds}..., msgType:{msgType}, length:{length}"; #endregion 로그용 문자열 함수들 } //============================================================================================= // 리슨 역할을 하는 세션 기반 클래스 이다. (서버 역할용) // // author : kangms // //============================================================================================= public abstract partial class ListenSessionBase : SessionBase { private readonly string m_server_type = string.Empty; private NetworkAddress m_listen_address = new(); private LargePacketHandler m_large_packet_handler = new(); // SESSION_ID 는 Pround.HostID 와 같다 !!! private readonly ConcurrentDictionary m_entity_with_sessions = new(); public ListenSessionBase(IRmiHost netForServer, string serverType) : base(netForServer) { m_server_type = serverType; } protected override bool onBindRmiHostHandler(IRmiHost currRmiHost) { var err_msg = string.Empty; var rmi_host_for_server = currRmiHost as NetServer; if(null == rmi_host_for_server) { err_msg = $"Invalid Param !!!, NetServer is null - {toBasicString()}"; Log.getLogger().error(err_msg); return false; } rmi_host_for_server.ClientJoinHandler = onConnectedClient; rmi_host_for_server.ClientLeaveHandler = onDisconnectedClient; rmi_host_for_server.ErrorHandler = onError; rmi_host_for_server.WarningHandler = onWarning; rmi_host_for_server.InformationHandler = onInformation; rmi_host_for_server.ExceptionHandler = onException; rmi_host_for_server.NoRmiProcessedHandler = onNoRmiProcessed; rmi_host_for_server.ClientHackSuspectedHandler = onClientHackSuspected; return true; } private async void onConnectedClient(NetClientInfo clientInfo) { var err_msg = string.Empty; var new_entity_with_session = await onNewEntityWithSession(clientInfo); if(null == new_entity_with_session) { err_msg = $"Failed to create New EnityWithSession - {toBasicString()}"; Log.getLogger().fatal(err_msg); return; } if(false == m_entity_with_sessions.TryAdd(clientInfo.getSessionId(), new_entity_with_session)) { err_msg = $"Already registered EnityWithSession !!! : {new_entity_with_session.toBasicString()} - {toBasicString()}"; Log.getLogger().fatal(err_msg); return; } new_entity_with_session.setListenSessionBase(this); NamedPipeMonitor.SetCurrentClientConnection(m_entity_with_sessions.Count, getServerType().toServerType()); var initializer = new_entity_with_session as IInitializer; if(null != initializer) { var result = await initializer.onInit(); if(result.isFail()) { Log.getLogger().fatal(result.toBasicString()); return; } } var hostId = clientInfo.hostID; err_msg = $"Client connected, in onConnectedClient() : hostPublicIP:{clientInfo.tcpAddrFromServer.IPToString()}, HostId:{hostId}, {new_entity_with_session.toBasicString()} - {toBasicString()}"; Log.getLogger().debug(err_msg); } private async void onDisconnectedClient(NetClientInfo clientInfo, ErrorInfo errorinfo, ByteArray comment) { var err_msg = string.Empty; if (clientInfo == null || errorinfo == null) { string clientInfo_log = clientInfo == null ? "Null" : "Not Null"; string errorInfo_log = errorinfo == null ? "Null" : "Not Null"; err_msg = $"onDisconnectedClient clientInfo is null !!! clientInfo : {clientInfo_log}, errorinfo : {errorInfo_log}"; Log.getLogger().fatal(err_msg); return; } var hostId = clientInfo.hostID; var errInfo = errorinfo.GetString(); var comm = comment == null ? string.Empty : Encoding.Default.GetString(comment.data); err_msg = $"Client Disconnected, in onDisconnectedClient() : hostPublicIP:{clientInfo.tcpAddrFromServer.IPToString()}, HostId:{hostId}, ErrorInfo:{errInfo}, comment:{comm} - {toBasicString()}"; Log.getLogger().debug(err_msg); if (false == m_entity_with_sessions.TryGetValue(clientInfo.getSessionId(), out var found_entity_with_session)) { NamedPipeMonitor.SetCurrentClientConnection(m_entity_with_sessions.Count, getServerType().toServerType()); err_msg = $"Not found EnityWithSession !!! : toDisconnectSessionId:{clientInfo.getSessionId()} - {toBasicString()}"; Log.getLogger().error(err_msg); return; } if(false == m_entity_with_sessions.TryRemove(clientInfo.getSessionId(), out _)) { NamedPipeMonitor.SetCurrentClientConnection(m_entity_with_sessions.Count, getServerType().toServerType()); err_msg = $"Failed to remove EnityWithSession !!! : {found_entity_with_session.toBasicString()} - {toBasicString()}"; Log.getLogger().error(err_msg); return; } NamedPipeMonitor.SetCurrentClientConnection(m_entity_with_sessions.Count, getServerType().toServerType()); await onDisconnectedEntityWithSession(found_entity_with_session); } public bool disconnectClient(SESSION_ID sessionId) { var rmi_host_for_server = getRmiHost() as NetServer; if (rmi_host_for_server == null) return false; return rmi_host_for_server.CloseConnection(sessionId.toHostID()); } private void onError(ErrorInfo errorInfo) { var err_msg = errorInfo == null ? string.Empty : errorInfo.GetString() ?? string.Empty; Log.getLogger().error($"ProudNet Error !!!, called onError() : errMsg:{err_msg} - {toBasicString()}"); } private void onWarning(ErrorInfo errorInfo) { var err_msg = errorInfo == null ? string.Empty : errorInfo.GetString() ?? string.Empty; Log.getLogger().warn($"ProudNet Warning !!!, called onWarning() : errMsg:{err_msg} - {toBasicString()}"); } private void onInformation(ErrorInfo errorInfo) { var err_msg = errorInfo == null ? string.Empty : errorInfo.GetString() ?? string.Empty; Log.getLogger().info($"ProudNet Information !!!, called onInformation() : errMsg:{err_msg} - {toBasicString()}"); } private void onException(Exception e) { Log.getLogger().error($"ProudNet Exception !!!, called onException() : errMsg:{e} - {toBasicString()}"); } private void onNoRmiProcessed(RmiID rmiID) { Log.getLogger().warn($"ProudNet NoRmiProcessed !!!, called onNoRmiProcessed() : RmiId:{rmiID} - {toBasicString()}"); } private void onClientHackSuspected(Nettention.Proud.HostID clientID, HackType hackType) { Log.getLogger().error($"ProudNet Client Hack Suspencted !!!, called onClientHackSuspected() : HostId:{clientID}), HackType:{hackType} - {toBasicString()}"); } public override IEntityWithSession? onLookupEntityWithSession(SESSION_ID sessionId) { m_entity_with_sessions.TryGetValue(sessionId, out var found_entity_with_session); return found_entity_with_session; } #region 로그용 문자열 함수들 public override string toBasicString() => $"NetServerInfo: ServerType:{getServerType()}"; #endregion 로그용 문자열 함수들 #region 재정의 해야 하는 함수들 protected abstract Task onNewEntityWithSession(NetClientInfo clientInfo); protected abstract Task onDisconnectedEntityWithSession(IEntityWithSession disconnectedEntity); public abstract int getMaxConnectionCount(); #endregion 재정의 해야 하는 함수들 } //=========================================================================================== // 서버로 연결할 세션 기반 클래스 이다. (클라이언트 역할용) // // author : kangms // //=========================================================================================== public abstract partial class ConnectToServerSessionBase : SessionBase { private string m_to_connect_server_type = string.Empty; // 연결할 호스트 정보 private string m_host_ip = string.Empty; private UInt16 m_host_port; private string m_host_address = string.Empty; public ConnectToServerSessionBase(IRmiHost netForClient) : base(netForClient) { } protected override bool onBindRmiHostHandler(IRmiHost currRmiHost) { var err_msg = string.Empty; var rmi_host_for_client = currRmiHost as NetClient; if (null == rmi_host_for_client) { err_msg = $"Invalid Param !!!, NetClient is null - {toBasicString()}"; Log.getLogger().error(err_msg); return false; } return true; } #region 로그용 문자열 함수들 public override string toBasicString() => $"NetClientInfo: TargetServerType:{getToConnectServerType()}, TargetAddress:{getHostAddress()}"; #endregion 로그용 문자열 함수들 }