internal class ReliableUdpConnectionControlBlock : IDisposable { // . public ConcurrentDictionary<Tuple<EndPoint, Int32>, byte[]> IncomingStreams { get; private set;} // . . public ConcurrentDictionary<Tuple<EndPoint, Int32>, byte[]> OutcomingStreams { get; private set; } // connection record . private readonly ConcurrentDictionary<Tuple<EndPoint, Int32>, ReliableUdpConnectionRecord> m_listOfHandlers; // . private readonly List<ReliableUdpSubscribeObject> m_subscribers; // private Socket m_socketIn; // private int m_port; // IP private IPAddress m_ipAddress; // public IPEndPoint LocalEndpoint { get; private set; } // // public StatesCollection States { get; private set; } // . TransmissionId private readonly RNGCryptoServiceProvider m_randomCrypto; //... }
private void Receive() { EndPoint connectedClient = new IPEndPoint(IPAddress.Any, 0); // , socket.BeginReceiveFrom byte[] buffer = new byte[DefaultMaxPacketSize + ReliableUdpHeader.Length]; // this.m_socketIn.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref connectedClient, EndReceive, buffer); } private void EndReceive(IAsyncResult ar) { EndPoint connectedClient = new IPEndPoint(IPAddress.Any, 0); int bytesRead = this.m_socketIn.EndReceiveFrom(ar, ref connectedClient); // , Receive(); // .. - // IAsyncResult.AsyncState byte[] bytes = ((byte[]) ar.AsyncState).Slice(0, bytesRead); // ReliableUdpHeader header; if (!ReliableUdpStateTools.ReadReliableUdpHeader(bytes, out header)) { // - return; } // connection record' Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(connectedClient, header.TransmissionId); // connection record ReliableUdpConnectionRecord record = m_listOfHandlers.GetOrAdd(key, new ReliableUdpConnectionRecord(key, this, header.ReliableUdpMessageType)); // record.State.ReceivePacket(record, header, bytes); }
internal class ReliableUdpConnectionRecord : IDisposable { // public byte[] IncomingStream { get; set; } // public ReliableUdpState State { get; set; } // , connection record // public Tuple<EndPoint, Int32> Key { get; private set;} // public int WindowLowerBound; // public readonly int WindowSize; // public int SndNext; // public int NumberOfPackets; // ( Tuple) // public readonly Int32 TransmissionId; // IP endpoint – public readonly IPEndPoint RemoteClient; // , IP // MTU – (IP.Header + UDP.Header + RelaibleUDP.Header) public readonly int BufferSize; // public readonly ReliableUdpConnectionControlBlock Tcb; // BeginSendMessage/EndSendMessage public readonly AsyncResultSendMessage AsyncResult; // public bool IsNoAnswerNeeded; // ( ) public int RcvCurrent; // public int[] LostPackets { get; private set; } // . bool. public int IsLastPacketReceived = 0; //... }
protected virtual void DisposeByTimeout(object record) { ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record; if (record.AsyncResult != null) { connectionRecord.AsyncResult.SetAsCompleted(false); } connectionRecord.Dispose(); }
protected override void DisposeByTimeout(object record) { ReliableUdpConnectionRecord connectionRecord = (ReliableUdpConnectionRecord) record; // SetAsCompleted(connectionRecord); }
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { if (connectionRecord.IsDone != 0) return; if (!ReliableUdpStateTools.CheckForNoPacketLoss(connectionRecord, connectionRecord.IsLastPacketReceived != 0)) { // , foreach (int seqNum in connectionRecord.LostPackets) { if (seqNum != 0) { ReliableUdpStateTools.SendAskForLostPacket(connectionRecord, seqNum); } } // , if (!connectionRecord.TimerSecondTry) { connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); connectionRecord.TimerSecondTry = true; return; } // WaitForPacketTimer // - StartCloseWaitTimer(connectionRecord); } else if (connectionRecord.IsLastPacketReceived != 0) // { // ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); connectionRecord.State = connectionRecord.Tcb.States.Completed; connectionRecord.State.ProcessPackets(connectionRecord); // // , , // ack . // - // Completed StartCloseWaitTimer(connectionRecord); } // , ack else { if (!connectionRecord.TimerSecondTry) { ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); connectionRecord.TimerSecondTry = true; return; } // StartCloseWaitTimer(connectionRecord); } }
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { if (connectionRecord.IsDone != 0) return; // // ( - , ) ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, connectionRecord.SndNext - 1)); // CloseWait – StartCloseWaitTimer(connectionRecord); }
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { if (connectionRecord.WaitForPacketsTimer != null) connectionRecord.WaitForPacketsTimer.Dispose(); // ReliableUdpStateTools.CreateMessageFromMemoryStream(connectionRecord); }
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket)) // return; // - FirstPacket LastPacket - if (header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket) & header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket)) { ReliableUdpStateTools.CreateMessageFromSinglePacket(connectionRecord, header, payload.Slice(ReliableUdpHeader.Length, payload.Length)); if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk)) { // ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); } SetAsCompleted(connectionRecord); return; } // by design packet numbers 0; if (header.PacketNumber != 0) return; ReliableUdpStateTools.InitIncomingBytesStorage(connectionRecord, header); ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload); // - , connectionRecord.NumberOfPackets = (int)Math.Ceiling((double) ((double) connectionRecord.IncomingStream.Length/(double) connectionRecord.BufferSize)); // (0) connectionRecord.RcvCurrent = header.PacketNumber; // 1 connectionRecord.WindowLowerBound++; // connectionRecord.State = connectionRecord.Tcb.States.Assembling; // // if (header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk)) { connectionRecord.CloseWaitTimer = new Timer(DisposeByTimeout, connectionRecord, connectionRecord.ShortTimerPeriod, -1); } else { ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1); } }
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { if (connectionRecord.IsDone != 0) return; if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.RequestForPacket)) return; // // + 1, int windowHighestBound = Math.Min((connectionRecord.WindowLowerBound + connectionRecord.WindowSize), (connectionRecord.NumberOfPackets)); // if (header.PacketNumber < connectionRecord.WindowLowerBound || header.PacketNumber > windowHighestBound) return; connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // : if (header.PacketNumber == connectionRecord.NumberOfPackets) { // Interlocked.Increment(ref connectionRecord.IsDone); SetAsCompleted(connectionRecord); return; } // c if ((header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket) && header.PacketNumber == 1)) { // SendPacket(connectionRecord); } // else if (header.PacketNumber == windowHighestBound) { // / connectionRecord.WindowLowerBound += connectionRecord.WindowSize; // connectionRecord.WindowControlArray.Nullify(); // SendPacket(connectionRecord); } // – else ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, header.PacketNumber)); }
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { if (connectionRecord.IsDone != 0) return; // if (header.Flags.HasFlag(ReliableUdpHeaderFlags.NoAsk)) { // connectionRecord.CloseWaitTimer.Change(connectionRecord.LongTimerPeriod, -1); // ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload); // - if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket)) { connectionRecord.State = connectionRecord.Tcb.States.Completed; connectionRecord.State.ProcessPackets(connectionRecord); } return; } // int windowHighestBound = Math.Min((connectionRecord.WindowLowerBound + connectionRecord.WindowSize - 1), (connectionRecord.NumberOfPackets - 1)); // if (header.PacketNumber < connectionRecord.WindowLowerBound || header.PacketNumber > (windowHighestBound)) return; // if (connectionRecord.WindowControlArray.Contains(header.PacketNumber)) return; // ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload); // connectionRecord.PacketCounter++; // connectionRecord.WindowControlArray[header.PacketNumber - connectionRecord.WindowLowerBound] = header.PacketNumber; // if (header.PacketNumber > connectionRecord.RcvCurrent) connectionRecord.RcvCurrent = header.PacketNumber; // connectionRecord.TimerSecondTry = false; connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket)) { Interlocked.Increment(ref connectionRecord.IsLastPacketReceived); } // , // else if (connectionRecord.PacketCounter == connectionRecord.WindowSize) { // . connectionRecord.PacketCounter = 0; // connectionRecord.WindowLowerBound += connectionRecord.WindowSize; // connectionRecord.WindowControlArray.Nullify(); ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); } // if (Thread.VolatileRead(ref connectionRecord.IsLastPacketReceived) != 0) { // ProcessPackets(connectionRecord); } }
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { // , // ack if (header.Flags.HasFlag(ReliableUdpHeaderFlags.LastPacket)) { ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); } }
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord) { connectionRecord.PacketCounter = 0; connectionRecord.SndNext = 0; connectionRecord.WindowLowerBound = 0; // - // if (connectionRecord.IsNoAnswerNeeded) { // As Is do { ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, ReliableUdpStateTools. CreateReliableUdpHeader(connectionRecord))); connectionRecord.SndNext++; } while (connectionRecord.SndNext < connectionRecord.NumberOfPackets); SetAsCompleted(connectionRecord); return; } // ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord); ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header)); // connectionRecord.SndNext++; // connectionRecord.WindowLowerBound++; connectionRecord.State = connectionRecord.Tcb.States.SendingCycle; // connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1); }
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord) { // for (connectionRecord.PacketCounter = 0; connectionRecord.PacketCounter < connectionRecord.WindowSize && connectionRecord.SndNext < connectionRecord.NumberOfPackets; connectionRecord.PacketCounter++) { ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord); ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header)); connectionRecord.SndNext++; } // , connectionRecord.WaitForPacketsTimer.Change( connectionRecord.ShortTimerPeriod, -1 ); if ( connectionRecord.CloseWaitTimer != null ) { connectionRecord.CloseWaitTimer.Change( -1, -1 ); } }
private void StartTransmission(ReliableUdpMessage reliableUdpMessage, EndPoint endPoint, AsyncResultSendMessage asyncResult) { if (m_isListenerStarted == 0) { if (this.LocalEndpoint == null) { throw new ArgumentNullException( "", "You must use constructor with parameters or start listener before sending message" ); } // StartListener(LocalEndpoint); } // , EndPoint ReliableUdpHeader.TransmissionId byte[] transmissionId = new byte[4]; // transmissionId m_randomCrypto.GetBytes(transmissionId); Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(endPoint, BitConverter.ToInt32(transmissionId, 0)); // , // if (!m_listOfHandlers.TryAdd(key, new ReliableUdpConnectionRecord(key, this, reliableUdpMessage, asyncResult))) { // – m_randomCrypto.GetBytes(transmissionId); key = new Tuple<EndPoint, Int32>(endPoint, BitConverter.ToInt32(transmissionId, 0)); if (!m_listOfHandlers.TryAdd(key, new ReliableUdpConnectionRecord(key, this, reliableUdpMessage, asyncResult))) // – throw new ArgumentException("Pair TransmissionId & EndPoint is already exists in the dictionary"); } // m_listOfHandlers[key].State.SendPacket(m_listOfHandlers[key]); }
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord) { connectionRecord.PacketCounter = 0; connectionRecord.SndNext = 0; connectionRecord.WindowLowerBound = 0; // ... // ReliableUdpHeader header = ReliableUdpStateTools.CreateReliableUdpHeader(connectionRecord); ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.CreateUdpPayload(connectionRecord, header)); // connectionRecord.SndNext++; // connectionRecord.WindowLowerBound++; // SendingCycle connectionRecord.State = connectionRecord.Tcb.States.SendingCycle; // connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1); }
private void EndReceive(IAsyncResult ar) { // ... // // ReliableUdpHeader header; if (!ReliableUdpStateTools.ReadReliableUdpHeader(bytes, out header)) { // - return; } // connection record' Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(connectedClient, header.TransmissionId); // connection record ReliableUdpConnectionRecord record = m_listOfHandlers.GetOrAdd(key, new ReliableUdpConnectionRecord(key, this, header. ReliableUdpMessageType)); // record.State.ReceivePacket(record, header, bytes); }
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { if (!header.Flags.HasFlag(ReliableUdpHeaderFlags.FirstPacket)) // return; // ... // by design packet numbers 0; if (header.PacketNumber != 0) return; // ReliableUdpStateTools.InitIncomingBytesStorage(connectionRecord, header); // ReliableUdpStateTools.WritePacketData(connectionRecord, header, payload); // - , connectionRecord.NumberOfPackets = (int)Math.Ceiling((double) ((double) connectionRecord.IncomingStream.Length/(double) connectionRecord.BufferSize)); // (0) connectionRecord.RcvCurrent = header.PacketNumber; // 1 connectionRecord.WindowLowerBound++; // connectionRecord.State = connectionRecord.Tcb.States.Assembling; if (/* */) // ... else { // ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); connectionRecord.WaitForPacketsTimer = new Timer(CheckByTimer, connectionRecord, connectionRecord.ShortTimerPeriod, -1); } }
public override void SendPacket(ReliableUdpConnectionRecord connectionRecord) { // // ... // connectionRecord.WaitForPacketsTimer.Change( connectionRecord.ShortTimerPeriod, -1 ); if ( connectionRecord.CloseWaitTimer != null ) connectionRecord.CloseWaitTimer.Change( -1, -1 ); }
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { // ... // connectionRecord.TimerSecondTry = false; connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // ... }
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { // ... if (/* */) { // // , if (!connectionRecord.TimerSecondTry) { connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); connectionRecord.TimerSecondTry = true; return; } // WaitForPacketTimer // - StartCloseWaitTimer(connectionRecord); } else if (/* */) { // ... StartCloseWaitTimer(connectionRecord); } // ack else { if (!connectionRecord.TimerSecondTry) { // ack connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); connectionRecord.TimerSecondTry = true; return; } // StartCloseWaitTimer(connectionRecord); } }
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { // ... // // ... // CloseWait – StartCloseWaitTimer(connectionRecord); }
protected void StartCloseWaitTimer(ReliableUdpConnectionRecord connectionRecord) { if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(connectionRecord.LongTimerPeriod, -1); else connectionRecord.CloseWaitTimer = new Timer(DisposeByTimeout, connectionRecord, connectionRecord.LongTimerPeriod, -1); }
public void Dispose() { try { System.Threading.Monitor.Enter(this.LockerReceive); } finally { Interlocked.Increment(ref this.IsDone); if (WaitForPacketsTimer != null) { WaitForPacketsTimer.Dispose(); } if (CloseWaitTimer != null) { CloseWaitTimer.Dispose(); } byte[] stream; Tcb.IncomingStreams.TryRemove(Key, out stream); stream = null; Tcb.OutcomingStreams.TryRemove(Key, out stream); stream = null; System.Threading.Monitor.Exit(this.LockerReceive); } }
public override void ProcessPackets(ReliableUdpConnectionRecord connectionRecord) { //... if (!ReliableUdpStateTools.CheckForNoPacketLoss(connectionRecord, connectionRecord.IsLastPacketReceived != 0)) { // , foreach (int seqNum in connectionRecord.LostPackets) { if (seqNum != 0) { ReliableUdpStateTools.SendAskForLostPacket(connectionRecord, seqNum); } } // ... } }
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { // ... connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); // if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // ... // – else ReliableUdpStateTools.SendPacket(connectionRecord, ReliableUdpStateTools.RetransmissionCreateUdpPayload(connectionRecord, header.PacketNumber)); }
public override void ReceivePacket(ReliableUdpConnectionRecord connectionRecord, ReliableUdpHeader header, byte[] payload) { // ... // connectionRecord.PacketCounter++; // connectionRecord.WindowControlArray[header.PacketNumber - connectionRecord.WindowLowerBound] = header.PacketNumber; // if (header.PacketNumber > connectionRecord.RcvCurrent) connectionRecord.RcvCurrent = header.PacketNumber; // connectionRecord.TimerSecondTry = false; connectionRecord.WaitForPacketsTimer.Change(connectionRecord.ShortTimerPeriod, -1); if (connectionRecord.CloseWaitTimer != null) connectionRecord.CloseWaitTimer.Change(-1, -1); // ... // , // else if (connectionRecord.PacketCounter == connectionRecord.WindowSize) { // . connectionRecord.PacketCounter = 0; // connectionRecord.WindowLowerBound += connectionRecord.WindowSize; // connectionRecord.WindowControlArray.Nullify(); ReliableUdpStateTools.SendAcknowledgePacket(connectionRecord); } // ... }
public sealed class ReliableUdp : IDisposable { // public IPEndPoint LocalEndpoint // ReliableUdp // IP // . 0 // public ReliableUdp(IPAddress localAddress, int port = 0) // public ReliableUdpSubscribeObject SubscribeOnMessages(ReliableUdpMessageCallback callback, ReliableUdpMessageTypes messageType = ReliableUdpMessageTypes.Any, IPEndPoint ipEndPoint = null) // public void Unsubscribe(ReliableUdpSubscribeObject subscribeObject) // // : XP Server 2003 , .. .NET Framework 4.0 public Task<bool> SendMessageAsync(ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteEndPoint, CancellationToken cToken) // public IAsyncResult BeginSendMessage(ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteEndPoint, AsyncCallback asyncCallback, Object state) // public bool EndSendMessage(IAsyncResult asyncResult) // public void Dispose() }
public delegate void ReliableUdpMessageCallback( ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteClient );
public class ReliableUdpMessage { // , public ReliableUdpMessageTypes Type { get; private set; } // public byte[] Body { get; private set; } // true – // public bool NoAsk { get; private set; } }
public enum ReliableUdpMessageTypes : short { // Any = 0, // STUN server StunRequest = 1, // STUN server StunResponse = 2, // FileTransfer =3, // ... }
public IAsyncResult BeginSendMessage(ReliableUdpMessage reliableUdpMessage, IPEndPoint remoteEndPoint, AsyncCallback asyncCallback, Object state)
public bool EndSendMessage(IAsyncResult asyncResult)
Source: https://habr.com/ru/post/250227/
All Articles