/// <summary> /// Sends byte[] to socket. /// Creates datagram with frame format given as example in demonstration example. /// Switches state to waitingforack. /// Set sendAsIs when sending/resending valid datagram/frame. /// </summary> /// <param name="data">Byte array to be sent over socket</param> /// <param name="sendAsIs">Boolen: true - datagram has been contructed before, false - construct new datagram and send it</param> protected virtual async void RdtSend(byte[] data, bool sendAsIs = false) { if (sendAsIs) { socket.Send(data); } else { switch (state) { case (int)STATE.WaitingCallFromAboveOrBelow: { byte[] newDatagram = rdt.MakeDatagram(data, senderSeq); socket.Send(newDatagram); previouslySentDatagram = newDatagram; state = (int)STATE.WaitingForAck; break; } case (int)STATE.WaitingForAck: { RaiseOnDeliver(InvokeReason.Error, "Waiting for ACK/NACK, add to queue."); messageBuffer.Add(data); break; } } } }
private async void RdtSend(byte[] data, bool isOldDatagram = false) { if (isOldDatagram) { /*data has been sent before so it has seq nums etc*/ socket.Send(data); } else { /*data is just new content as byte[] so new datagram is needed*/ /*nextseqnum<base+N will fail when seqnum range overflows*/ if (rdt.Distmod(gbnBase, gbnNextSeqNum, gbnWindowSize) < gbnWindowSize - 1) { try { OnDeliver?.Invoke(InvokeReason.Debug, "4a" + PrintGbnDebug()); byte[] newDatagram = rdt.MakeDatagram(data, gbnNextSeqNum); gbnSendDictionary[gbnNextSeqNum] = newDatagram; socket.Send(gbnSendDictionary[gbnNextSeqNum]); //simplify with pre-increment and combine following operations gbnNextSeqNum = gbnNextSeqNum + 1; gbnNextSeqNum = gbnNextSeqNum % gbnWindowSize; OnDeliver?.Invoke(InvokeReason.Debug, "4b" + PrintGbnDebug()); if (cts != null) { cts.Cancel(); } /*All standing packets are ack'd*/ if (gbnBase == gbnNextSeqNum) { //OnDeliver?.Invoke(InvokeReason.Debug, "Sending window is empty."); } else { //start new timer //TODO: Check if this leaks resources CancellationTokenSource aCTS = new CancellationTokenSource(); cts = aCTS; await Timertimeout(aCTS.Token); /* * if (cts == aCTS) * { * cts = null; * } */ } } catch (OperationCanceledException) { } } else //send window is full { OnDeliver?.Invoke(InvokeReason.Error, "Sending window is full, try again later."); } } }
private async void RdtSend(byte[] data, bool isOldDatagram = false) { if (isOldDatagram) { socket.Send(data); } else { byte[] datagram = rdt.MakeDatagram(data, srNextSeqNum); sendBucket.AddToBucket(datagram, srNextSeqNum); if (rdt.IsSeqInRange(srNextSeqNum, srSendBase, (byte)(srSendBase + srWindowSize - 1))) { //Send via socket socket.Send(datagram); sendBucket.MarkAsSent(srNextSeqNum); //start timer for this packet or set timestamp to simulate via single timer sendBucket.SetTimestamp(srNextSeqNum); OnDeliver?.Invoke(InvokeReason.Debug, "Message sent" + PrintSRDebugInfo()); } else { OnDeliver?.Invoke(InvokeReason.Debug, "Message Buffered" + PrintSRDebugInfo()); } srNextSeqNum++; //pre-increment is more efficient here? edit: compiler optimization -> no difference } }