Host.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #region License
  2. /*
  3. ENet for C#
  4. Copyright (c) 2011 James F. Bellinger <jfb@zer7.com>
  5. Permission to use, copy, modify, and/or distribute this software for any
  6. purpose with or without fee is hereby granted, provided that the above
  7. copyright notice and this permission notice appear in all copies.
  8. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #endregion
  17. using Log;
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Threading.Tasks;
  21. namespace ENet
  22. {
  23. public sealed unsafe class Host : IDisposable
  24. {
  25. private Native.ENetHost* host;
  26. private readonly PeerManager peerManager = new PeerManager();
  27. private readonly object eventsLock = new object();
  28. private Action events;
  29. public Host(ushort port, uint peerLimit):
  30. this(new Address { Port = port }, peerLimit)
  31. {
  32. }
  33. public Host(Address? address, uint peerLimit, uint channelLimit = 0,
  34. uint incomingBandwidth = 0, uint outgoingBandwidth = 0, bool enableCrc = true)
  35. {
  36. if (peerLimit > Native.ENET_PROTOCOL_MAXIMUM_PEER_ID)
  37. {
  38. throw new ArgumentOutOfRangeException("peerLimit");
  39. }
  40. CheckChannelLimit(channelLimit);
  41. if (address != null)
  42. {
  43. Native.ENetAddress nativeAddress = address.Value.NativeData;
  44. this.host = Native.enet_host_create(
  45. ref nativeAddress, peerLimit, channelLimit, incomingBandwidth,
  46. outgoingBandwidth);
  47. }
  48. else
  49. {
  50. this.host = Native.enet_host_create(
  51. null, peerLimit, channelLimit, incomingBandwidth,
  52. outgoingBandwidth);
  53. }
  54. if (this.host == null)
  55. {
  56. throw new ENetException(0, "Host creation call failed.");
  57. }
  58. if (enableCrc)
  59. {
  60. Native.enet_enable_crc(host);
  61. }
  62. }
  63. ~Host()
  64. {
  65. this.Dispose(false);
  66. }
  67. public void Dispose()
  68. {
  69. this.Dispose(true);
  70. GC.SuppressFinalize(this);
  71. }
  72. private void Dispose(bool disposing)
  73. {
  74. if (this.host == null)
  75. {
  76. return;
  77. }
  78. if (disposing)
  79. {
  80. Native.enet_host_destroy(this.host);
  81. }
  82. this.host = null;
  83. }
  84. private static void CheckChannelLimit(uint channelLimit)
  85. {
  86. if (channelLimit > Native.ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
  87. {
  88. throw new ArgumentOutOfRangeException("channelLimit");
  89. }
  90. }
  91. private int CheckEvents(out Event e)
  92. {
  93. Native.ENetEvent nativeEvent;
  94. int ret = Native.enet_host_check_events(this.host, out nativeEvent);
  95. e = new Event(this, nativeEvent);
  96. return ret;
  97. }
  98. private int Service(int timeout)
  99. {
  100. if (timeout < 0)
  101. {
  102. throw new ArgumentOutOfRangeException("timeout");
  103. }
  104. return Native.enet_host_service(this.host, null, (uint)timeout);
  105. }
  106. private int Service(int timeout, out Event e)
  107. {
  108. if (timeout < 0)
  109. {
  110. throw new ArgumentOutOfRangeException("timeout");
  111. }
  112. Native.ENetEvent nativeEvent;
  113. int ret = Native.enet_host_service(this.host, out nativeEvent, (uint)timeout);
  114. e = new Event(this, nativeEvent);
  115. return ret;
  116. }
  117. public PeerManager Peers
  118. {
  119. get
  120. {
  121. return peerManager;
  122. }
  123. }
  124. public void Broadcast(byte channelID, ref Packet packet)
  125. {
  126. Native.enet_host_broadcast(this.host, channelID, packet.NativeData);
  127. packet.NativeData = null; // Broadcast automatically clears this.
  128. }
  129. public void CompressWithRangeEncoder()
  130. {
  131. Native.enet_host_compress_with_range_encoder(this.host);
  132. }
  133. public void DoNotCompress()
  134. {
  135. Native.enet_host_compress(this.host, null);
  136. }
  137. public Task<Peer> ConnectAsync(
  138. Address address, uint channelLimit = Native.ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT,
  139. uint data = 0)
  140. {
  141. CheckChannelLimit(channelLimit);
  142. var tcs = new TaskCompletionSource<Peer>();
  143. Native.ENetAddress nativeAddress = address.NativeData;
  144. Native.ENetPeer* p = Native.enet_host_connect(this.host, ref nativeAddress, channelLimit, data);
  145. if (p == null)
  146. {
  147. throw new ENetException(0, "Host connect call failed.");
  148. }
  149. var peer = new Peer(this, p);
  150. peer.Connected += e => tcs.TrySetResult(e.Peer);
  151. return tcs.Task;
  152. }
  153. public void Flush()
  154. {
  155. Native.enet_host_flush(this.host);
  156. }
  157. public void SetBandwidthLimit(uint incomingBandwidth, uint outgoingBandwidth)
  158. {
  159. Native.enet_host_bandwidth_limit(this.host, incomingBandwidth, outgoingBandwidth);
  160. }
  161. public void SetChannelLimit(uint channelLimit)
  162. {
  163. CheckChannelLimit(channelLimit);
  164. Native.enet_host_channel_limit(this.host, channelLimit);
  165. }
  166. public event Action Events
  167. {
  168. add
  169. {
  170. lock (eventsLock)
  171. {
  172. events += value;
  173. }
  174. }
  175. remove
  176. {
  177. lock (eventsLock)
  178. {
  179. events -= value;
  180. }
  181. }
  182. }
  183. private void OnExecuteEvents()
  184. {
  185. Action local = null;
  186. lock (eventsLock)
  187. {
  188. if (events == null)
  189. {
  190. return;
  191. }
  192. local = events;
  193. events = null;
  194. }
  195. local();
  196. }
  197. public void Run()
  198. {
  199. // 处理其它线程扔过来的事件
  200. OnExecuteEvents();
  201. if (this.Service(0) < 0)
  202. {
  203. return;
  204. }
  205. Event e;
  206. while (this.CheckEvents(out e) > 0)
  207. {
  208. switch (e.Type)
  209. {
  210. case EventType.Connect:
  211. {
  212. e.Peer.OnConnected(e);
  213. break;
  214. }
  215. case EventType.Receive:
  216. {
  217. e.Peer.OnReceived(e);
  218. break;
  219. }
  220. case EventType.Disconnect:
  221. {
  222. e.Peer.OnDisconnect(e);
  223. break;
  224. }
  225. }
  226. }
  227. }
  228. }
  229. }