AppServer.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Reflection;
  8. using System.Security.Authentication;
  9. using System.Security.Cryptography.X509Certificates;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using SuperSocket.Common;
  14. using SuperSocket.SocketBase.Command;
  15. using SuperSocket.SocketBase.Config;
  16. using SuperSocket.SocketBase.Protocol;
  17. using SuperSocket.SocketBase.Security;
  18. namespace SuperSocket.SocketBase
  19. {
  20. /// <summary>
  21. /// AppServer class
  22. /// </summary>
  23. public class AppServer : AppServer<AppSession>
  24. {
  25. /// <summary>
  26. /// Initializes a new instance of the <see cref="AppServer"/> class.
  27. /// </summary>
  28. public AppServer()
  29. : base()
  30. {
  31. }
  32. /// <summary>
  33. /// Initializes a new instance of the <see cref="AppServer"/> class.
  34. /// </summary>
  35. /// <param name="receiveFilterFactory">The Receive filter factory.</param>
  36. public AppServer(IReceiveFilterFactory<StringRequestInfo> receiveFilterFactory)
  37. : base(receiveFilterFactory)
  38. {
  39. }
  40. }
  41. /// <summary>
  42. /// AppServer class
  43. /// </summary>
  44. /// <typeparam name="TAppSession">The type of the app session.</typeparam>
  45. public class AppServer<TAppSession> : AppServer<TAppSession, StringRequestInfo>
  46. where TAppSession : AppSession<TAppSession, StringRequestInfo>, IAppSession, new()
  47. {
  48. /// <summary>
  49. /// Initializes a new instance of the <see cref="AppServer&lt;TAppSession&gt;"/> class.
  50. /// </summary>
  51. public AppServer()
  52. : base()
  53. {
  54. }
  55. /// <summary>
  56. /// Initializes a new instance of the <see cref="AppServer&lt;TAppSession&gt;"/> class.
  57. /// </summary>
  58. /// <param name="receiveFilterFactory">The Receive filter factory.</param>
  59. public AppServer(IReceiveFilterFactory<StringRequestInfo> receiveFilterFactory)
  60. : base(receiveFilterFactory)
  61. {
  62. }
  63. internal override IReceiveFilterFactory<StringRequestInfo> CreateDefaultReceiveFilterFactory()
  64. {
  65. return new CommandLineReceiveFilterFactory(TextEncoding);
  66. }
  67. }
  68. /// <summary>
  69. /// AppServer basic class
  70. /// </summary>
  71. /// <typeparam name="TAppSession">The type of the app session.</typeparam>
  72. /// <typeparam name="TRequestInfo">The type of the request info.</typeparam>
  73. public abstract class AppServer<TAppSession, TRequestInfo> : AppServerBase<TAppSession, TRequestInfo>
  74. where TRequestInfo : class, IRequestInfo
  75. where TAppSession : AppSession<TAppSession, TRequestInfo>, IAppSession, new()
  76. {
  77. /// <summary>
  78. /// Initializes a new instance of the <see cref="AppServer&lt;TAppSession, TRequestInfo&gt;"/> class.
  79. /// </summary>
  80. public AppServer()
  81. : base()
  82. {
  83. }
  84. /// <summary>
  85. /// Initializes a new instance of the <see cref="AppServer&lt;TAppSession, TRequestInfo&gt;"/> class.
  86. /// </summary>
  87. /// <param name="protocol">The protocol.</param>
  88. protected AppServer(IReceiveFilterFactory<TRequestInfo> protocol)
  89. : base(protocol)
  90. {
  91. }
  92. internal override IReceiveFilterFactory<TRequestInfo> CreateDefaultReceiveFilterFactory()
  93. {
  94. return null;
  95. }
  96. /// <summary>
  97. /// Starts this AppServer instance.
  98. /// </summary>
  99. /// <returns></returns>
  100. public override bool Start()
  101. {
  102. if (!base.Start())
  103. return false;
  104. if (!Config.DisableSessionSnapshot)
  105. StartSessionSnapshotTimer();
  106. if (Config.ClearIdleSession)
  107. StartClearSessionTimer();
  108. return true;
  109. }
  110. private ConcurrentDictionary<string, TAppSession> m_SessionDict = new ConcurrentDictionary<string, TAppSession>(StringComparer.OrdinalIgnoreCase);
  111. /// <summary>
  112. /// Registers the session into the session container.
  113. /// </summary>
  114. /// <param name="sessionID">The session ID.</param>
  115. /// <param name="appSession">The app session.</param>
  116. /// <returns></returns>
  117. protected override bool RegisterSession(string sessionID, TAppSession appSession)
  118. {
  119. if (m_SessionDict.TryAdd(sessionID, appSession))
  120. return true;
  121. if (Logger.IsErrorEnabled)
  122. Logger.Error(appSession, "The session is refused because the it's ID already exists!");
  123. return false;
  124. }
  125. /// <summary>
  126. /// Gets the app session by ID.
  127. /// </summary>
  128. /// <param name="sessionID">The session ID.</param>
  129. /// <returns></returns>
  130. [Obsolete("Use the method GetSessionByID instead")]
  131. public TAppSession GetAppSessionByID(string sessionID)
  132. {
  133. return GetSessionByID(sessionID);
  134. }
  135. /// <summary>
  136. /// Gets the app session by ID.
  137. /// </summary>
  138. /// <param name="sessionID">The session ID.</param>
  139. /// <returns></returns>
  140. public override TAppSession GetSessionByID(string sessionID)
  141. {
  142. if (string.IsNullOrEmpty(sessionID))
  143. return NullAppSession;
  144. TAppSession targetSession;
  145. m_SessionDict.TryGetValue(sessionID, out targetSession);
  146. return targetSession;
  147. }
  148. /// <summary>
  149. /// Called when [socket session closed].
  150. /// </summary>
  151. /// <param name="session">The session.</param>
  152. /// <param name="reason">The reason.</param>
  153. protected override void OnSessionClosed(TAppSession session, CloseReason reason)
  154. {
  155. string sessionID = session.SessionID;
  156. if (!string.IsNullOrEmpty(sessionID))
  157. {
  158. TAppSession removedSession;
  159. if (!m_SessionDict.TryRemove(sessionID, out removedSession))
  160. {
  161. if (Logger.IsErrorEnabled)
  162. Logger.Error(session, "Failed to remove this session, Because it has't been in session container!");
  163. }
  164. }
  165. base.OnSessionClosed(session, reason);
  166. }
  167. /// <summary>
  168. /// Gets the total session count.
  169. /// </summary>
  170. public override int SessionCount
  171. {
  172. get
  173. {
  174. return m_SessionDict.Count;
  175. }
  176. }
  177. #region Clear idle sessions
  178. private System.Threading.Timer m_ClearIdleSessionTimer = null;
  179. private void StartClearSessionTimer()
  180. {
  181. int interval = Config.ClearIdleSessionInterval * 1000;//in milliseconds
  182. m_ClearIdleSessionTimer = new System.Threading.Timer(ClearIdleSession, new object(), interval, interval);
  183. }
  184. /// <summary>
  185. /// Clears the idle session.
  186. /// </summary>
  187. /// <param name="state">The state.</param>
  188. private void ClearIdleSession(object state)
  189. {
  190. if (Monitor.TryEnter(state))
  191. {
  192. try
  193. {
  194. var sessionSource = SessionSource;
  195. if (sessionSource == null)
  196. return;
  197. DateTime now = DateTime.Now;
  198. DateTime timeOut = now.AddSeconds(0 - Config.IdleSessionTimeOut);
  199. var timeOutSessions = sessionSource.Where(s => s.Value.LastActiveTime <= timeOut).Select(s => s.Value);
  200. System.Threading.Tasks.Parallel.ForEach(timeOutSessions, s =>
  201. {
  202. if (Logger.IsInfoEnabled)
  203. 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));
  204. s.Close(CloseReason.TimeOut);
  205. });
  206. }
  207. catch (Exception e)
  208. {
  209. if(Logger.IsErrorEnabled)
  210. Logger.Error("Clear idle session error!", e);
  211. }
  212. finally
  213. {
  214. Monitor.Exit(state);
  215. }
  216. }
  217. }
  218. private KeyValuePair<string, TAppSession>[] SessionSource
  219. {
  220. get
  221. {
  222. if (Config.DisableSessionSnapshot)
  223. return m_SessionDict.ToArray();
  224. else
  225. return m_SessionsSnapshot;
  226. }
  227. }
  228. #endregion
  229. #region Take session snapshot
  230. private System.Threading.Timer m_SessionSnapshotTimer = null;
  231. private KeyValuePair<string, TAppSession>[] m_SessionsSnapshot = new KeyValuePair<string, TAppSession>[0];
  232. private void StartSessionSnapshotTimer()
  233. {
  234. int interval = Math.Max(Config.SessionSnapshotInterval, 1) * 1000;//in milliseconds
  235. m_SessionSnapshotTimer = new System.Threading.Timer(TakeSessionSnapshot, new object(), interval, interval);
  236. }
  237. private void TakeSessionSnapshot(object state)
  238. {
  239. if (Monitor.TryEnter(state))
  240. {
  241. Interlocked.Exchange(ref m_SessionsSnapshot, m_SessionDict.ToArray());
  242. Monitor.Exit(state);
  243. }
  244. }
  245. #endregion
  246. #region Search session utils
  247. /// <summary>
  248. /// Gets the matched sessions from sessions snapshot.
  249. /// </summary>
  250. /// <param name="critera">The prediction critera.</param>
  251. /// <returns></returns>
  252. public override IEnumerable<TAppSession> GetSessions(Func<TAppSession, bool> critera)
  253. {
  254. var sessionSource = SessionSource;
  255. if (sessionSource == null)
  256. return null;
  257. return sessionSource.Select(p => p.Value).Where(critera);
  258. }
  259. /// <summary>
  260. /// Gets all sessions in sessions snapshot.
  261. /// </summary>
  262. /// <returns></returns>
  263. public override IEnumerable<TAppSession> GetAllSessions()
  264. {
  265. var sessionSource = SessionSource;
  266. if (sessionSource == null)
  267. return null;
  268. return sessionSource.Select(p => p.Value);
  269. }
  270. /// <summary>
  271. /// Stops this instance.
  272. /// </summary>
  273. public override void Stop()
  274. {
  275. base.Stop();
  276. if (m_SessionSnapshotTimer != null)
  277. {
  278. m_SessionSnapshotTimer.Change(Timeout.Infinite, Timeout.Infinite);
  279. m_SessionSnapshotTimer.Dispose();
  280. m_SessionSnapshotTimer = null;
  281. }
  282. if (m_ClearIdleSessionTimer != null)
  283. {
  284. m_ClearIdleSessionTimer.Change(Timeout.Infinite, Timeout.Infinite);
  285. m_ClearIdleSessionTimer.Dispose();
  286. m_ClearIdleSessionTimer = null;
  287. }
  288. m_SessionsSnapshot = null;
  289. var sessions = m_SessionDict.ToArray();
  290. if (sessions.Length > 0)
  291. {
  292. var tasks = new Task[sessions.Length];
  293. for (var i = 0; i < tasks.Length; i++)
  294. {
  295. tasks[i] = Task.Factory.StartNew((s) =>
  296. {
  297. var session = s as TAppSession;
  298. if (session != null)
  299. {
  300. session.Close(CloseReason.ServerShutdown);
  301. }
  302. }, sessions[i].Value);
  303. }
  304. Task.WaitAll(tasks);
  305. }
  306. }
  307. #endregion
  308. }
  309. }