USocket.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Threading.Tasks;
  5. using Common.Network;
  6. namespace UNet
  7. {
  8. internal sealed class USocket: IDisposable
  9. {
  10. private IntPtr peerPtr;
  11. private readonly Queue<byte[]> recvQueue = new Queue<byte[]>();
  12. public Action<ENetEvent> Connected { get; set; }
  13. public Action<ENetEvent> Received { get; private set; }
  14. public Action<ENetEvent> Disconnect { get; private set; }
  15. private void Dispose(bool disposing)
  16. {
  17. if (this.peerPtr == IntPtr.Zero)
  18. {
  19. return;
  20. }
  21. NativeMethods.ENetPeerReset(this.peerPtr);
  22. this.peerPtr = IntPtr.Zero;
  23. }
  24. public USocket(IntPtr peerPtr)
  25. {
  26. this.peerPtr = peerPtr;
  27. }
  28. ~USocket()
  29. {
  30. this.Dispose(false);
  31. }
  32. public void Dispose()
  33. {
  34. this.Dispose(true);
  35. GC.SuppressFinalize(this);
  36. }
  37. public IntPtr PeerPtr
  38. {
  39. get
  40. {
  41. return this.peerPtr;
  42. }
  43. }
  44. private ENetPeer Struct
  45. {
  46. get
  47. {
  48. if (this.peerPtr == IntPtr.Zero)
  49. {
  50. return new ENetPeer();
  51. }
  52. ENetPeer peer = (ENetPeer) Marshal.PtrToStructure(this.peerPtr, typeof (ENetPeer));
  53. return peer;
  54. }
  55. set
  56. {
  57. Marshal.StructureToPtr(value, this.peerPtr, false);
  58. }
  59. }
  60. public string RemoteAddress
  61. {
  62. get
  63. {
  64. ENetPeer peer = this.Struct;
  65. return peer.Address.Host + ":" + peer.Address.Port;
  66. }
  67. }
  68. public void Ping()
  69. {
  70. NativeMethods.ENetPeerPing(this.peerPtr);
  71. }
  72. public void ConfigureThrottle(uint interval, uint acceleration, uint deceleration)
  73. {
  74. NativeMethods.ENetPeerThrottleConfigure(this.peerPtr, interval, acceleration, deceleration);
  75. }
  76. public void SendAsync(byte[] data, byte channelID = 0, PacketFlags flags = PacketFlags.Reliable)
  77. {
  78. UPacket packet = new UPacket(data, flags);
  79. NativeMethods.ENetPeerSend(this.peerPtr, channelID, packet.PacketPtr);
  80. // enet_peer_send函数会自动删除packet,设置为0,防止Dispose或者析构函数再次删除
  81. packet.PacketPtr = IntPtr.Zero;
  82. }
  83. public Task<byte[]> RecvAsync()
  84. {
  85. var tcs = new TaskCompletionSource<byte[]>();
  86. // 如果有缓存的包,从缓存中取
  87. if (this.recvQueue.Count > 0)
  88. {
  89. byte[] bytes = this.recvQueue.Dequeue();
  90. tcs.TrySetResult(bytes);
  91. }
  92. // 没有缓存封包,设置回调等待
  93. else
  94. {
  95. this.Received = eEvent =>
  96. {
  97. if (eEvent.Type == EventType.Disconnect)
  98. {
  99. tcs.TrySetException(new UException("socket disconnected in receive"));
  100. }
  101. using (UPacket packet = new UPacket(eEvent.Packet))
  102. {
  103. byte[] bytes = packet.Bytes;
  104. tcs.TrySetResult(bytes);
  105. }
  106. };
  107. }
  108. return tcs.Task;
  109. }
  110. public Task<bool> DisconnectAsync(uint data = 0)
  111. {
  112. NativeMethods.ENetPeerDisconnect(this.peerPtr, data);
  113. // EnetPeerDisconnect会reset Peer,这里设置为0,防止再次Dispose
  114. this.peerPtr = IntPtr.Zero;
  115. var tcs = new TaskCompletionSource<bool>();
  116. this.Disconnect = eEvent => tcs.TrySetResult(true);
  117. return tcs.Task;
  118. }
  119. public Task<bool> DisconnectLaterAsync(uint data = 0)
  120. {
  121. NativeMethods.ENetPeerDisconnectLater(this.peerPtr, data);
  122. // EnetPeerDisconnect会reset Peer,这里设置为0,防止再次Dispose
  123. this.peerPtr = IntPtr.Zero;
  124. var tcs = new TaskCompletionSource<bool>();
  125. this.Disconnect = eEvent => tcs.TrySetResult(true);
  126. return tcs.Task;
  127. }
  128. public void DisconnectNow(uint data)
  129. {
  130. NativeMethods.ENetPeerDisconnectNow(this.peerPtr, data);
  131. // EnetPeerDisconnect会reset Peer,这里设置为0,防止再次Dispose
  132. this.peerPtr = IntPtr.Zero;
  133. }
  134. internal void OnConnected(ENetEvent eNetEvent)
  135. {
  136. if (this.Connected == null)
  137. {
  138. return;
  139. }
  140. Action<ENetEvent> localConnected = this.Connected;
  141. this.Connected = null;
  142. // 此调用将让await ConnectAsync返回,所以null必须在此之前设置
  143. localConnected(eNetEvent);
  144. }
  145. internal void OnReceived(ENetEvent eNetEvent)
  146. {
  147. // 如果应用层还未调用readasync则将包放到缓存队列
  148. if (this.Received == null)
  149. {
  150. using (UPacket packet = new UPacket(eNetEvent.Packet))
  151. {
  152. byte[] bytes = packet.Bytes;
  153. this.recvQueue.Enqueue(bytes);
  154. }
  155. }
  156. else
  157. {
  158. Action<ENetEvent> localReceived = this.Received;
  159. this.Received = null;
  160. // 此调用将让await ReadAsync返回,所以null必须在此之前设置
  161. localReceived(eNetEvent);
  162. }
  163. }
  164. internal void OnDisconnect(ENetEvent eNetEvent)
  165. {
  166. if (this.Disconnect == null)
  167. {
  168. return;
  169. }
  170. Action<ENetEvent> localDisconnect = this.Disconnect;
  171. this.Disconnect = null;
  172. localDisconnect(eNetEvent);
  173. }
  174. }
  175. }