UdpSocketServer.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. using System.Text;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. using SuperSocket.Common;
  10. using SuperSocket.SocketBase;
  11. using SuperSocket.SocketBase.Command;
  12. using SuperSocket.SocketBase.Protocol;
  13. using SuperSocket.SocketEngine.AsyncSocket;
  14. namespace SuperSocket.SocketEngine
  15. {
  16. class UdpSocketServer<TRequestInfo> : SocketServerBase, IActiveConnector
  17. where TRequestInfo : IRequestInfo
  18. {
  19. private IPEndPoint m_EndPointIPv4;
  20. private IPEndPoint m_EndPointIPv6;
  21. private bool m_IsUdpRequestInfo = false;
  22. private IReceiveFilter<TRequestInfo> m_UdpRequestFilter;
  23. private int m_ConnectionCount = 0;
  24. private IRequestHandler<TRequestInfo> m_RequestHandler;
  25. /// <summary>
  26. /// Initializes a new instance of the <see cref="UdpSocketServer&lt;TRequestInfo&gt;"/> class.
  27. /// </summary>
  28. /// <param name="appServer">The app server.</param>
  29. /// <param name="listeners">The listeners.</param>
  30. public UdpSocketServer(IAppServer appServer, ListenerInfo[] listeners)
  31. : base(appServer, listeners)
  32. {
  33. m_RequestHandler = appServer as IRequestHandler<TRequestInfo>;
  34. m_EndPointIPv4 = new IPEndPoint(IPAddress.Any, 0);
  35. m_EndPointIPv6 = new IPEndPoint(IPAddress.IPv6Any, 0);
  36. m_IsUdpRequestInfo = typeof(TRequestInfo).IsSubclassOf(typeof(UdpRequestInfo));
  37. m_UdpRequestFilter = ((IReceiveFilterFactory<TRequestInfo>)appServer.ReceiveFilterFactory).CreateFilter(appServer, null, null);
  38. }
  39. /// <summary>
  40. /// Called when [new client accepted].
  41. /// </summary>
  42. /// <param name="listener">The listener.</param>
  43. /// <param name="client">The client.</param>
  44. /// <param name="state">The state.</param>
  45. protected override void OnNewClientAccepted(ISocketListener listener, Socket client, object state)
  46. {
  47. var paramArray = state as object[];
  48. var receivedData = paramArray[0] as byte[];
  49. var socketAddress = paramArray[1] as SocketAddress;
  50. var remoteEndPoint = (socketAddress.Family == AddressFamily.InterNetworkV6 ? m_EndPointIPv6.Create(socketAddress) : m_EndPointIPv4.Create(socketAddress)) as IPEndPoint;
  51. try
  52. {
  53. if (m_IsUdpRequestInfo)
  54. {
  55. ProcessPackageWithSessionID(client, remoteEndPoint, receivedData);
  56. }
  57. else
  58. {
  59. ProcessPackageWithoutSessionID(client, remoteEndPoint, receivedData);
  60. }
  61. }
  62. catch (Exception e)
  63. {
  64. if (AppServer.Logger.IsErrorEnabled)
  65. AppServer.Logger.Error("Process UDP package error!", e);
  66. }
  67. }
  68. IAppSession CreateNewSession(Socket listenSocket, IPEndPoint remoteEndPoint, string sessionID)
  69. {
  70. if (!DetectConnectionNumber(remoteEndPoint))
  71. return null;
  72. var socketSession = new UdpSocketSession(listenSocket, remoteEndPoint, sessionID);
  73. var appSession = AppServer.CreateAppSession(socketSession);
  74. if (appSession == null)
  75. return null;
  76. if (!DetectConnectionNumber(remoteEndPoint))
  77. return null;
  78. if (!AppServer.RegisterSession(appSession))
  79. return null;
  80. Interlocked.Increment(ref m_ConnectionCount);
  81. socketSession.Closed += OnSocketSessionClosed;
  82. socketSession.Start();
  83. return appSession;
  84. }
  85. void ProcessPackageWithSessionID(Socket listenSocket, IPEndPoint remoteEndPoint, byte[] receivedData)
  86. {
  87. TRequestInfo requestInfo;
  88. string sessionID;
  89. int rest;
  90. try
  91. {
  92. requestInfo = this.m_UdpRequestFilter.Filter(receivedData, 0, receivedData.Length, false, out rest);
  93. }
  94. catch (Exception exc)
  95. {
  96. if(AppServer.Logger.IsErrorEnabled)
  97. AppServer.Logger.Error("Failed to parse UDP package!", exc);
  98. return;
  99. }
  100. var udpRequestInfo = requestInfo as UdpRequestInfo;
  101. if (rest > 0)
  102. {
  103. if (AppServer.Logger.IsErrorEnabled)
  104. AppServer.Logger.Error("The output parameter rest must be zero in this case!");
  105. return;
  106. }
  107. if (udpRequestInfo == null)
  108. {
  109. if (AppServer.Logger.IsErrorEnabled)
  110. AppServer.Logger.Error("Invalid UDP package format!");
  111. return;
  112. }
  113. if (string.IsNullOrEmpty(udpRequestInfo.SessionID))
  114. {
  115. if (AppServer.Logger.IsErrorEnabled)
  116. AppServer.Logger.Error("Failed to get session key from UDP package!");
  117. return;
  118. }
  119. sessionID = udpRequestInfo.SessionID;
  120. var appSession = AppServer.GetSessionByID(sessionID);
  121. if (appSession == null)
  122. {
  123. appSession = CreateNewSession(listenSocket, remoteEndPoint, sessionID);
  124. //Failed to create a new session
  125. if (appSession == null)
  126. return;
  127. }
  128. else
  129. {
  130. var socketSession = appSession.SocketSession as UdpSocketSession;
  131. //Client remote endpoint may change, so update session to ensure the server can find client correctly
  132. socketSession.UpdateRemoteEndPoint(remoteEndPoint);
  133. }
  134. m_RequestHandler.ExecuteCommand(appSession, requestInfo);
  135. }
  136. void ProcessPackageWithoutSessionID(Socket listenSocket, IPEndPoint remoteEndPoint, byte[] receivedData)
  137. {
  138. var sessionID = remoteEndPoint.ToString();
  139. var appSession = AppServer.GetSessionByID(sessionID);
  140. if (appSession == null) //New session
  141. {
  142. appSession = CreateNewSession(listenSocket, remoteEndPoint, sessionID);
  143. //Failed to create a new session
  144. if (appSession == null)
  145. return;
  146. appSession.ProcessRequest(receivedData, 0, receivedData.Length, false);
  147. }
  148. else //Existing session
  149. {
  150. appSession.ProcessRequest(receivedData, 0, receivedData.Length, false);
  151. }
  152. }
  153. void OnSocketSessionClosed(ISocketSession socketSession, CloseReason closeReason)
  154. {
  155. Interlocked.Decrement(ref m_ConnectionCount);
  156. }
  157. bool DetectConnectionNumber(EndPoint remoteEndPoint)
  158. {
  159. if (m_ConnectionCount >= AppServer.Config.MaxConnectionNumber)
  160. {
  161. if (AppServer.Logger.IsErrorEnabled)
  162. AppServer.Logger.ErrorFormat("Cannot accept a new UDP connection from {0}, the max connection number {1} has been exceed!",
  163. remoteEndPoint.ToString(), AppServer.Config.MaxConnectionNumber);
  164. return false;
  165. }
  166. return true;
  167. }
  168. protected override ISocketListener CreateListener(ListenerInfo listenerInfo)
  169. {
  170. return new UdpSocketListener(listenerInfo);
  171. }
  172. public override void ResetSessionSecurity(IAppSession session, System.Security.Authentication.SslProtocols security)
  173. {
  174. throw new NotSupportedException();
  175. }
  176. Task<ActiveConnectResult> IActiveConnector.ActiveConnect(EndPoint targetEndPoint)
  177. {
  178. return ((IActiveConnector)this).ActiveConnect(targetEndPoint, null);
  179. }
  180. Task<ActiveConnectResult> IActiveConnector.ActiveConnect(EndPoint targetEndPoint, EndPoint localEndPoint)
  181. {
  182. var taskSource = new TaskCompletionSource<ActiveConnectResult>();
  183. var socket = new Socket(targetEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
  184. if (localEndPoint != null)
  185. {
  186. socket.ExclusiveAddressUse = false;
  187. socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
  188. socket.Bind(localEndPoint);
  189. }
  190. var session = CreateNewSession(socket, (IPEndPoint)targetEndPoint, targetEndPoint.ToString());
  191. if (session == null)
  192. taskSource.SetException(new Exception("Failed to create session for this socket."));
  193. else
  194. taskSource.SetResult(new ActiveConnectResult { Result = true, Session = session });
  195. return taskSource.Task;
  196. }
  197. }
  198. }