USocket.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Threading.Tasks;
  5. using Network;
  6. namespace UNet
  7. {
  8. public sealed class USocket: IDisposable
  9. {
  10. private IntPtr peerPtr = IntPtr.Zero;
  11. private readonly EService service;
  12. private readonly LinkedList<byte[]> recvBuffer = new LinkedList<byte[]>();
  13. public Action<EEvent> Connected { get; set; }
  14. public Action<EEvent> Received { get; set; }
  15. public Action<EEvent> Disconnect { get; set; }
  16. public Action<int> Error { get; set; }
  17. public USocket(EService service)
  18. {
  19. this.service = service;
  20. }
  21. private void Dispose(bool disposing)
  22. {
  23. if (this.peerPtr == IntPtr.Zero)
  24. {
  25. return;
  26. }
  27. NativeMethods.EnetPeerReset(this.peerPtr);
  28. this.peerPtr = IntPtr.Zero;
  29. }
  30. ~USocket()
  31. {
  32. Dispose(false);
  33. }
  34. public void Dispose()
  35. {
  36. Dispose(true);
  37. GC.SuppressFinalize(this);
  38. }
  39. public IntPtr PeerPtr
  40. {
  41. get
  42. {
  43. return this.peerPtr;
  44. }
  45. set
  46. {
  47. this.peerPtr = value;
  48. }
  49. }
  50. private ENetPeer Struct
  51. {
  52. get
  53. {
  54. if (this.peerPtr == IntPtr.Zero)
  55. {
  56. return new ENetPeer();
  57. }
  58. ENetPeer peer = (ENetPeer) Marshal.PtrToStructure(this.peerPtr, typeof (ENetPeer));
  59. return peer;
  60. }
  61. set
  62. {
  63. Marshal.StructureToPtr(value, this.peerPtr, false);
  64. }
  65. }
  66. public string RemoteAddress
  67. {
  68. get
  69. {
  70. ENetPeer peer = this.Struct;
  71. return peer.Address.Host + ":" + peer.Address.Port;
  72. }
  73. }
  74. public void Ping()
  75. {
  76. NativeMethods.EnetPeerPing(this.peerPtr);
  77. }
  78. public void ConfigureThrottle(uint interval, uint acceleration, uint deceleration)
  79. {
  80. NativeMethods.EnetPeerThrottleConfigure(this.peerPtr, interval, acceleration, deceleration);
  81. }
  82. public Task<bool> ConnectAsync(
  83. string hostName, ushort port,
  84. uint channelLimit = NativeMethods.ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT, uint data = 0)
  85. {
  86. if (channelLimit > NativeMethods.ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
  87. {
  88. throw new ArgumentOutOfRangeException("channelLimit");
  89. }
  90. var tcs = new TaskCompletionSource<bool>();
  91. Address address = new Address { HostName = hostName, Port = port };
  92. ENetAddress nativeAddress = address.Struct;
  93. this.peerPtr = NativeMethods.EnetHostConnect(this.service.HostPtr, ref nativeAddress,
  94. channelLimit, data);
  95. if (this.peerPtr == IntPtr.Zero)
  96. {
  97. throw new EException("host connect call failed.");
  98. }
  99. this.service.PeersManager.Add(this.peerPtr, this);
  100. this.Connected = eEvent =>
  101. {
  102. if (eEvent.EventState == EventState.DISCONNECTED)
  103. {
  104. tcs.TrySetException(new EException("socket disconnected in connect"));
  105. }
  106. tcs.TrySetResult(true);
  107. };
  108. return tcs.Task;
  109. }
  110. public Task<bool> AcceptAsync()
  111. {
  112. if (this.service.PeersManager.ContainsKey(IntPtr.Zero))
  113. {
  114. throw new EException("do not accept twice!");
  115. }
  116. var tcs = new TaskCompletionSource<bool>();
  117. // 如果有请求连接缓存的包,从缓存中取
  118. if (this.service.ConnEEvents.Count > 0)
  119. {
  120. EEvent eEvent = this.service.ConnEEvents.First.Value;
  121. this.service.ConnEEvents.RemoveFirst();
  122. this.PeerPtr = eEvent.PeerPtr;
  123. this.service.PeersManager.Add(this.PeerPtr, this);
  124. tcs.TrySetResult(true);
  125. }
  126. else
  127. {
  128. this.service.PeersManager.Add(this.PeerPtr, this);
  129. this.Connected = eEvent =>
  130. {
  131. if (eEvent.EventState == EventState.DISCONNECTED)
  132. {
  133. tcs.TrySetException(new EException("socket disconnected in accpet"));
  134. }
  135. this.service.PeersManager.Remove(IntPtr.Zero);
  136. this.PeerPtr = eEvent.PeerPtr;
  137. this.service.PeersManager.Add(this.PeerPtr, this);
  138. tcs.TrySetResult(true);
  139. };
  140. }
  141. return tcs.Task;
  142. }
  143. public void WriteAsync(byte[] data, byte channelID = 0, PacketFlags flags = PacketFlags.Reliable)
  144. {
  145. var packet = new EPacket(data, flags);
  146. NativeMethods.EnetPeerSend(this.peerPtr, channelID, packet.PacketPtr);
  147. // enet_peer_send函数会自动删除packet,设置为0,防止Dispose或者析构函数再次删除
  148. packet.PacketPtr = IntPtr.Zero;
  149. }
  150. public Task<byte[]> ReadAsync()
  151. {
  152. var tcs = new TaskCompletionSource<byte[]>();
  153. // 如果有缓存的包,从缓存中取
  154. if (this.recvBuffer.Count > 0)
  155. {
  156. byte[] bytes = this.recvBuffer.First.Value;
  157. this.recvBuffer.RemoveFirst();
  158. tcs.TrySetResult(bytes);
  159. }
  160. // 没有缓存封包,设置回调等待
  161. else
  162. {
  163. this.Received = eEvent =>
  164. {
  165. if (eEvent.EventState == EventState.DISCONNECTED)
  166. {
  167. tcs.TrySetException(new EException("socket disconnected in receive"));
  168. }
  169. using (EPacket packet = new EPacket(eEvent.PacketPtr))
  170. {
  171. byte[] bytes = packet.Bytes;
  172. tcs.TrySetResult(bytes);
  173. }
  174. };
  175. }
  176. return tcs.Task;
  177. }
  178. public Task<bool> DisconnectAsync(uint data = 0)
  179. {
  180. NativeMethods.EnetPeerDisconnect(this.peerPtr, data);
  181. // EnetPeerDisconnect会reset Peer,这里设置为0,防止再次Dispose
  182. this.PeerPtr = IntPtr.Zero;
  183. var tcs = new TaskCompletionSource<bool>();
  184. this.Disconnect = eEvent => tcs.TrySetResult(true);
  185. return tcs.Task;
  186. }
  187. public Task<bool> DisconnectLaterAsync(uint data = 0)
  188. {
  189. NativeMethods.EnetPeerDisconnectLater(this.peerPtr, data);
  190. // EnetPeerDisconnect会reset Peer,这里设置为0,防止再次Dispose
  191. this.PeerPtr = IntPtr.Zero;
  192. var tcs = new TaskCompletionSource<bool>();
  193. this.Disconnect = eEvent => tcs.TrySetResult(true);
  194. return tcs.Task;
  195. }
  196. public void DisconnectNow(uint data)
  197. {
  198. NativeMethods.EnetPeerDisconnectNow(this.peerPtr, data);
  199. // EnetPeerDisconnect会reset Peer,这里设置为0,防止再次Dispose
  200. this.PeerPtr = IntPtr.Zero;
  201. }
  202. internal void OnConnected(EEvent eEvent)
  203. {
  204. if (this.Connected == null)
  205. {
  206. return;
  207. }
  208. Action<EEvent> localConnected = this.Connected;
  209. this.Connected = null;
  210. // 此调用将让await ConnectAsync返回,所以null必须在此之前设置
  211. localConnected(eEvent);
  212. }
  213. internal void OnReceived(EEvent eEvent)
  214. {
  215. // 如果应用层还未调用readasync则将包放到缓存队列
  216. if (this.Received == null)
  217. {
  218. using (var packet = new EPacket(eEvent.PacketPtr))
  219. {
  220. var bytes = packet.Bytes;
  221. this.recvBuffer.AddLast(bytes);
  222. }
  223. }
  224. else
  225. {
  226. Action<EEvent> localReceived = this.Received;
  227. this.Received = null;
  228. // 此调用将让await ReadAsync返回,所以null必须在此之前设置
  229. localReceived(eEvent);
  230. }
  231. }
  232. internal void OnDisconnect(EEvent eEvent)
  233. {
  234. if (this.Disconnect == null)
  235. {
  236. return;
  237. }
  238. this.Disconnect(eEvent);
  239. }
  240. internal void OnError(int errorCode)
  241. {
  242. if (this.Error == null)
  243. {
  244. return;
  245. }
  246. this.Error(errorCode);
  247. }
  248. }
  249. }