UdpSocketServer.cs 8.5 KB

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