using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; using System.Threading.Tasks; using SuperSocket.Common; using SuperSocket.SocketBase.Command; using SuperSocket.SocketBase.Config; using SuperSocket.SocketBase.Protocol; using SuperSocket.SocketBase.Security; namespace SuperSocket.SocketBase { /// /// AppServer class /// public class AppServer : AppServer { /// /// Initializes a new instance of the class. /// public AppServer() : base() { } /// /// Initializes a new instance of the class. /// /// The Receive filter factory. public AppServer(IReceiveFilterFactory receiveFilterFactory) : base(receiveFilterFactory) { } } /// /// AppServer class /// /// The type of the app session. public class AppServer : AppServer where TAppSession : AppSession, IAppSession, new() { /// /// Initializes a new instance of the class. /// public AppServer() : base() { } /// /// Initializes a new instance of the class. /// /// The Receive filter factory. public AppServer(IReceiveFilterFactory receiveFilterFactory) : base(receiveFilterFactory) { } internal override IReceiveFilterFactory CreateDefaultReceiveFilterFactory() { return new CommandLineReceiveFilterFactory(TextEncoding); } } /// /// AppServer basic class /// /// The type of the app session. /// The type of the request info. public abstract class AppServer : AppServerBase where TRequestInfo : class, IRequestInfo where TAppSession : AppSession, IAppSession, new() { /// /// Initializes a new instance of the class. /// public AppServer() : base() { } /// /// Initializes a new instance of the class. /// /// The protocol. protected AppServer(IReceiveFilterFactory protocol) : base(protocol) { } internal override IReceiveFilterFactory CreateDefaultReceiveFilterFactory() { return null; } /// /// Starts this AppServer instance. /// /// public override bool Start() { if (!base.Start()) return false; if (!Config.DisableSessionSnapshot) StartSessionSnapshotTimer(); if (Config.ClearIdleSession) StartClearSessionTimer(); return true; } private ConcurrentDictionary m_SessionDict = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); /// /// Registers the session into the session container. /// /// The session ID. /// The app session. /// protected override bool RegisterSession(string sessionID, TAppSession appSession) { if (m_SessionDict.TryAdd(sessionID, appSession)) return true; if (Logger.IsErrorEnabled) Logger.Error(appSession, "The session is refused because the it's ID already exists!"); return false; } /// /// Gets the app session by ID. /// /// The session ID. /// [Obsolete("Use the method GetSessionByID instead")] public TAppSession GetAppSessionByID(string sessionID) { return GetSessionByID(sessionID); } /// /// Gets the app session by ID. /// /// The session ID. /// public override TAppSession GetSessionByID(string sessionID) { if (string.IsNullOrEmpty(sessionID)) return NullAppSession; TAppSession targetSession; m_SessionDict.TryGetValue(sessionID, out targetSession); return targetSession; } /// /// Called when [socket session closed]. /// /// The session. /// The reason. protected override void OnSessionClosed(TAppSession session, CloseReason reason) { string sessionID = session.SessionID; if (!string.IsNullOrEmpty(sessionID)) { TAppSession removedSession; if (!m_SessionDict.TryRemove(sessionID, out removedSession)) { if (Logger.IsErrorEnabled) Logger.Error(session, "Failed to remove this session, Because it has't been in session container!"); } } base.OnSessionClosed(session, reason); } /// /// Gets the total session count. /// public override int SessionCount { get { return m_SessionDict.Count; } } #region Clear idle sessions private System.Threading.Timer m_ClearIdleSessionTimer = null; private void StartClearSessionTimer() { int interval = Config.ClearIdleSessionInterval * 1000;//in milliseconds m_ClearIdleSessionTimer = new System.Threading.Timer(ClearIdleSession, new object(), interval, interval); } /// /// Clears the idle session. /// /// The state. private void ClearIdleSession(object state) { if (Monitor.TryEnter(state)) { try { var sessionSource = SessionSource; if (sessionSource == null) return; DateTime now = DateTime.Now; DateTime timeOut = now.AddSeconds(0 - Config.IdleSessionTimeOut); var timeOutSessions = sessionSource.Where(s => s.Value.LastActiveTime <= timeOut).Select(s => s.Value); System.Threading.Tasks.Parallel.ForEach(timeOutSessions, s => { if (Logger.IsInfoEnabled) Logger.Info(s, string.Format("The session will be closed for {0} timeout, the session start time: {1}, last active time: {2}!", now.Subtract(s.LastActiveTime).TotalSeconds, s.StartTime, s.LastActiveTime)); s.Close(CloseReason.TimeOut); }); } catch (Exception e) { if(Logger.IsErrorEnabled) Logger.Error("Clear idle session error!", e); } finally { Monitor.Exit(state); } } } private KeyValuePair[] SessionSource { get { if (Config.DisableSessionSnapshot) return m_SessionDict.ToArray(); else return m_SessionsSnapshot; } } #endregion #region Take session snapshot private System.Threading.Timer m_SessionSnapshotTimer = null; private KeyValuePair[] m_SessionsSnapshot = new KeyValuePair[0]; private void StartSessionSnapshotTimer() { int interval = Math.Max(Config.SessionSnapshotInterval, 1) * 1000;//in milliseconds m_SessionSnapshotTimer = new System.Threading.Timer(TakeSessionSnapshot, new object(), interval, interval); } private void TakeSessionSnapshot(object state) { if (Monitor.TryEnter(state)) { Interlocked.Exchange(ref m_SessionsSnapshot, m_SessionDict.ToArray()); Monitor.Exit(state); } } #endregion #region Search session utils /// /// Gets the matched sessions from sessions snapshot. /// /// The prediction critera. /// public override IEnumerable GetSessions(Func critera) { var sessionSource = SessionSource; if (sessionSource == null) return null; return sessionSource.Select(p => p.Value).Where(critera); } /// /// Gets all sessions in sessions snapshot. /// /// public override IEnumerable GetAllSessions() { var sessionSource = SessionSource; if (sessionSource == null) return null; return sessionSource.Select(p => p.Value); } /// /// Stops this instance. /// public override void Stop() { base.Stop(); if (m_SessionSnapshotTimer != null) { m_SessionSnapshotTimer.Change(Timeout.Infinite, Timeout.Infinite); m_SessionSnapshotTimer.Dispose(); m_SessionSnapshotTimer = null; } if (m_ClearIdleSessionTimer != null) { m_ClearIdleSessionTimer.Change(Timeout.Infinite, Timeout.Infinite); m_ClearIdleSessionTimer.Dispose(); m_ClearIdleSessionTimer = null; } m_SessionsSnapshot = null; var sessions = m_SessionDict.ToArray(); if (sessions.Length > 0) { var tasks = new Task[sessions.Length]; for (var i = 0; i < tasks.Length; i++) { tasks[i] = Task.Factory.StartNew((s) => { var session = s as TAppSession; if (session != null) { session.Close(CloseReason.ServerShutdown); } }, sessions[i].Value); } Task.WaitAll(tasks); } } #endregion } }