WSServerProvider.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Threading;
  5. namespace IFramework.Net.WebSocket
  6. {
  7. using IFramework.Net.Tcp;
  8. internal class WSServerProvider : IDisposable, IWSServerProvider
  9. {
  10. private Encoding encoding = Encoding.UTF8;
  11. TcpServerProvider serverProvider = null;
  12. List<ConnectionInfo> ConnectionPool = null;
  13. System.Threading.Timer threadingTimer = null;
  14. int timeout = 1000 * 60 * 6;
  15. object lockobject = new object();
  16. public OnReceivedHandler OnReceived { get; set; }
  17. public OnReceivedSegmentHandler OnReceivedBytes { get; set; }
  18. public OnAcceptedHandler OnAccepted { get; set; }
  19. public OnDisconnectedHandler OnDisconnected { get; set; }
  20. public OnSentHandler OnSent { get; set; }
  21. public WSServerProvider(int maxConnections=32,int bufferSize=4096)
  22. {
  23. ConnectionPool = new List<ConnectionInfo>(maxConnections);
  24. serverProvider = new TcpServerProvider(maxConnections, bufferSize);
  25. //serverProvider.AcceptedCallback = new OnAcceptedHandler(AcceptedHandler);
  26. serverProvider.DisconnectedCallback = new OnDisconnectedHandler(DisconnectedHandler);
  27. serverProvider.ReceivedOffsetCallback = new OnReceivedSegmentHandler(ReceivedHandler);
  28. serverProvider.SentCallback = new OnSentHandler(SentHandler);
  29. threadingTimer = new System.Threading.Timer(new TimerCallback(TimingEvent), null, -1, -1);
  30. }
  31. public static WSServerProvider CreateProvider(int maxConnections = 32, int bufferSize = 4096)
  32. {
  33. return new WSServerProvider(maxConnections,bufferSize);
  34. }
  35. public void Dispose()
  36. {
  37. threadingTimer.Dispose();
  38. }
  39. private void TimingEvent(object obj)
  40. {
  41. lock (lockobject)
  42. {
  43. var items = ConnectionPool.FindAll(x => DateTime.Now.Subtract(x.ConnectedTime).TotalMilliseconds >= (timeout >> 1));
  44. foreach (var node in items)
  45. {
  46. if (DateTime.Now.Subtract(node.ConnectedTime).TotalMilliseconds >= timeout)
  47. {
  48. CloseAndRemove(node);
  49. continue;
  50. }
  51. SendPing(node.sToken);
  52. }
  53. }
  54. }
  55. public bool Start(int port,string ip="0.0.0.0")
  56. {
  57. bool isOk = serverProvider.Start(port,ip);
  58. if (isOk)
  59. {
  60. threadingTimer.Change(timeout>>1, timeout);
  61. }
  62. return isOk;
  63. }
  64. public void Stop()
  65. {
  66. threadingTimer.Change(-1, -1);
  67. lock (lockobject)
  68. {
  69. foreach (var node in ConnectionPool)
  70. {
  71. CloseAndRemove(node);
  72. }
  73. }
  74. }
  75. public void Close(SocketToken sToken)
  76. {
  77. serverProvider.Close(sToken);
  78. }
  79. public bool Send(SocketToken sToken, string content,bool waiting=true)
  80. {
  81. var buffer = new WebsocketFrame().ToSegmentFrame(content);
  82. return serverProvider.Send(new SegmentToken(sToken, buffer),waiting);
  83. }
  84. public bool Send(SegmentToken session,bool waiting=true)
  85. {
  86. return serverProvider.Send(session,waiting);
  87. }
  88. private void SendPing(SocketToken sToken)
  89. {
  90. serverProvider.Send(new SegmentToken(sToken, new byte[] { 0x89, 0x00 }));
  91. }
  92. private void SendPong(SegmentToken session)
  93. {
  94. var buffer = new WebsocketFrame().ToSegmentFrame(session.Data,OpCodeType.Bong);
  95. serverProvider.Send(new SegmentToken(session.sToken, buffer));
  96. }
  97. //private void AcceptedHandler(SocketToken sToken)
  98. //{
  99. //}
  100. private void DisconnectedHandler(SocketToken sToken)
  101. {
  102. // ConnectionPool.Remove(new ConnectionInfo() { sToken = sToken });
  103. Remove(sToken);
  104. if (OnDisconnected != null) OnDisconnected(sToken);
  105. }
  106. private void RefreshTimeout(SocketToken sToken)
  107. {
  108. foreach (var item in ConnectionPool)
  109. {
  110. if (item.sToken.TokenId == sToken.TokenId)
  111. {
  112. item.ConnectedTime = DateTime.Now;
  113. break;
  114. }
  115. }
  116. }
  117. private void ReceivedHandler(SegmentToken session)
  118. {
  119. var connection = ConnectionPool.Find(x => x.sToken.TokenId == session.sToken.TokenId);
  120. if (connection == null)
  121. {
  122. connection = new ConnectionInfo() { sToken = session.sToken };
  123. ConnectionPool.Add(connection);
  124. }
  125. if (connection.IsHandShaked == false)
  126. {
  127. var serverFrame = new WebsocketFrame();
  128. var access = serverFrame.GetHandshakePackage(session.Data);
  129. connection.IsHandShaked = access.IsHandShaked();
  130. if (connection.IsHandShaked == false)
  131. {
  132. CloseAndRemove(connection);
  133. return;
  134. }
  135. connection.ConnectedTime = DateTime.Now;
  136. var rsp = serverFrame.RspAcceptedFrame(access);
  137. serverProvider.Send(new SegmentToken(session.sToken, rsp));
  138. connection.accessInfo = access;
  139. if (OnAccepted != null) OnAccepted(session.sToken);
  140. }
  141. else
  142. {
  143. RefreshTimeout(session.sToken);
  144. WebsocketFrame packet = new WebsocketFrame();
  145. bool isOk = packet.DecodingFromBytes(session.Data, true);
  146. if (isOk == false) return;
  147. if (packet.OpCode == 0x01)//text
  148. {
  149. if (OnReceived != null)
  150. OnReceived(session.sToken, encoding.GetString(packet.Payload.buffer,
  151. packet.Payload.offset, packet.Payload.size));
  152. return;
  153. }
  154. else if (packet.OpCode == 0x08)//close
  155. {
  156. CloseAndRemove(connection);
  157. return;
  158. }
  159. else if (packet.OpCode == 0x09)//ping
  160. {
  161. SendPong(session);
  162. }
  163. else if (packet.OpCode == 0x0A)//pong
  164. {
  165. // SendPing(session.sToken);
  166. }
  167. if (OnReceivedBytes != null && packet.Payload.size>0)
  168. OnReceivedBytes(new SegmentToken(session.sToken, packet.Payload));
  169. }
  170. }
  171. private void SentHandler(SegmentToken session)
  172. {
  173. if (OnSent != null)
  174. {
  175. OnSent(session);
  176. }
  177. }
  178. private void CloseAndRemove(ConnectionInfo connection)
  179. {
  180. bool isOk = Remove(connection);
  181. if (isOk)
  182. {
  183. serverProvider.Close(connection.sToken);
  184. }
  185. }
  186. private bool Remove(ConnectionInfo info)
  187. {
  188. return ConnectionPool.Remove(info);
  189. }
  190. private bool Remove(SocketToken sToken)
  191. {
  192. return ConnectionPool.RemoveAll(x => x.sToken.TokenId == sToken.TokenId) > 0;
  193. }
  194. internal class ConnectionInfo : IComparable<SocketToken>
  195. {
  196. public SocketToken sToken { get; set; }
  197. public bool IsHandShaked { get; set; }
  198. public AccessInfo accessInfo { get; set; }
  199. public DateTime ConnectedTime { get; set; } = DateTime.MinValue;
  200. public int CompareTo(SocketToken info)
  201. {
  202. return sToken.TokenId - info.TokenId;
  203. }
  204. }
  205. }
  206. }