using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading.Tasks; using Common.Logger; using Network; namespace UNet { internal sealed class USocket : IDisposable { private IntPtr peerPtr; private readonly Queue recvQueue = new Queue(); public Action Connected { get; set; } public Action Received { get; private set; } public Action Disconnect { get; private set; } public Action Error { get; set; } private void Dispose(bool disposing) { if (this.peerPtr == IntPtr.Zero) { return; } NativeMethods.EnetPeerReset(this.peerPtr); this.peerPtr = IntPtr.Zero; } public USocket(IntPtr peerPtr) { this.peerPtr = peerPtr; } ~USocket() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public IntPtr PeerPtr { get { return this.peerPtr; } } private ENetPeer Struct { get { if (this.peerPtr == IntPtr.Zero) { return new ENetPeer(); } ENetPeer peer = (ENetPeer) Marshal.PtrToStructure(this.peerPtr, typeof (ENetPeer)); return peer; } set { Marshal.StructureToPtr(value, this.peerPtr, false); } } public string RemoteAddress { get { ENetPeer peer = this.Struct; return peer.Address.Host + ":" + peer.Address.Port; } } public void Ping() { NativeMethods.EnetPeerPing(this.peerPtr); } public void ConfigureThrottle(uint interval, uint acceleration, uint deceleration) { NativeMethods.EnetPeerThrottleConfigure(this.peerPtr, interval, acceleration, deceleration); } public void SendAsync(byte[] data, byte channelID = 0, PacketFlags flags = PacketFlags.Reliable) { UPacket packet = new UPacket(data, flags); NativeMethods.EnetPeerSend(this.peerPtr, channelID, packet.PacketPtr); // enet_peer_send函数会自动删除packet,设置为0,防止Dispose或者析构函数再次删除 packet.PacketPtr = IntPtr.Zero; } public Task RecvAsync() { var tcs = new TaskCompletionSource(); // 如果有缓存的包,从缓存中取 if (this.recvQueue.Count > 0) { byte[] bytes = this.recvQueue.Dequeue(); tcs.TrySetResult(bytes); } // 没有缓存封包,设置回调等待 else { this.Received = eEvent => { if (eEvent.Type == EventType.Disconnect) { tcs.TrySetException(new UException("socket disconnected in receive")); } using (UPacket packet = new UPacket(eEvent.Packet)) { byte[] bytes = packet.Bytes; tcs.TrySetResult(bytes); } }; } return tcs.Task; } public Task DisconnectAsync(uint data = 0) { NativeMethods.EnetPeerDisconnect(this.peerPtr, data); // EnetPeerDisconnect会reset Peer,这里设置为0,防止再次Dispose this.peerPtr = IntPtr.Zero; var tcs = new TaskCompletionSource(); this.Disconnect = eEvent => tcs.TrySetResult(true); return tcs.Task; } public Task DisconnectLaterAsync(uint data = 0) { NativeMethods.EnetPeerDisconnectLater(this.peerPtr, data); // EnetPeerDisconnect会reset Peer,这里设置为0,防止再次Dispose this.peerPtr = IntPtr.Zero; var tcs = new TaskCompletionSource(); this.Disconnect = eEvent => tcs.TrySetResult(true); return tcs.Task; } public void DisconnectNow(uint data) { NativeMethods.EnetPeerDisconnectNow(this.peerPtr, data); // EnetPeerDisconnect会reset Peer,这里设置为0,防止再次Dispose this.peerPtr = IntPtr.Zero; } internal void OnConnected(ENetEvent eNetEvent) { if (this.Connected == null) { return; } Action localConnected = this.Connected; this.Connected = null; // 此调用将让await ConnectAsync返回,所以null必须在此之前设置 localConnected(eNetEvent); } internal void OnReceived(ENetEvent eNetEvent) { // 如果应用层还未调用readasync则将包放到缓存队列 if (this.Received == null) { using (UPacket packet = new UPacket(eNetEvent.Packet)) { byte[] bytes = packet.Bytes; this.recvQueue.Enqueue(bytes); } } else { Action localReceived = this.Received; this.Received = null; // 此调用将让await ReadAsync返回,所以null必须在此之前设置 localReceived(eNetEvent); } } internal void OnDisconnect(ENetEvent eNetEvent) { if (this.Disconnect == null) { return; } Action localDisconnect = this.Disconnect; this.Disconnect = null; localDisconnect(eNetEvent); } } }