USocket.cs 4.8 KB

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