コード例 #1
0
        private void RdtReceive(byte[] datagram)
        {
            bool   isOk   = rdt.IsOk(datagram);
            string str    = rdt.GetDatagramContentString(datagram);
            bool   isAck  = rdt.IsAck(datagram);
            int    seqNum = rdt.GetSeqNum(datagram);

            if (isOk)
            {
                if (isAck)
                {
                    try
                    {
                        if (gbnBase != gbnNextSeqNum)
                        {
                            gbnSendDictionary.Remove(seqNum);
                            gbnBase = seqNum + 1;
                            gbnBase = gbnBase % gbnWindowSize;
                            //timer is running so stop/cancel

                            /*All standing packets are ack'd*/
                            if (gbnBase == gbnNextSeqNum)
                            {
                                OnDeliver?.Invoke(InvokeReason.Debug, "Has sent all pending messages successfully" + PrintGbnDebug());
                                if (cts != null)
                                {
                                    cts.Cancel();
                                }
                            }
                            else
                            {
                                OnDeliver?.Invoke(InvokeReason.Debug, "2" + PrintGbnDebug());
                                //start new timer

                                /*CancellationTokenSource aCTS = new CancellationTokenSource();
                                 * cts = aCTS;
                                 * await Timertimeout(aCTS.Token);
                                 * if (cts == aCTS)
                                 * {
                                 *  cts = null;
                                 * }*/
                            }
                        }
                    }
                    catch (OperationCanceledException) { }
                }
                else
                {
                    /*not ack, not corrupt*/
                    if (seqNum == gbnExpectedSeqNum)
                    {
                        gbnLatestAck = rdt.MakeAck(gbnExpectedSeqNum);
                        RdtSend(gbnLatestAck, true);
                        gbnExpectedSeqNum++;
                        gbnExpectedSeqNum = gbnExpectedSeqNum % gbnWindowSize;
                        //If there is a subscriber attached to OnDeliver (e.g. UI), invoke event.
                        OnDeliver?.Invoke(InvokeReason.Receiver, str);
                        OnDeliver?.Invoke(InvokeReason.Debug, "3" + PrintGbnDebug());
                    }
                    else
                    {
                        /*As in not waiting for any acks, ie is receiver*/
                        if (gbnSendDictionary.Count == 0)
                        {
                            OnDeliver?.Invoke(InvokeReason.Debug, "Unexpected ACK SEQ (lost packets or duplicates?), resending ACK for datagram: "
                                              + rdt.GetSeqNum(gbnLatestAck).ToString());
                            RdtSend(gbnLatestAck, true);
                        }
                    }
                }
            }
            else
            {
                /*corrupt
                 * Assuming we are receiver e.g. no outstanding acks
                 */
                if (gbnSendDictionary.Count == 0)
                {
                    OnDeliver?.Invoke(InvokeReason.Debug, "Corrupted datagram. Resending ACK with seq: "
                                      + rdt.GetSeqNum(gbnLatestAck).ToString());
                    RdtSend(gbnLatestAck, true);
                }
            }
        }
コード例 #2
0
        private void RdtReceive(byte[] datagram)
        {
            bool isOk = rdt.IsOk(datagram);

            if (isOk)
            {
                string str    = rdt.GetDatagramContentString(datagram);
                bool   isAck  = rdt.IsAck(datagram);
                byte   seqNum = (byte)rdt.GetSeqNum(datagram);

                if (isAck)
                {
                    //Mark as ack'd
                    //If seq == sendBase => move window by:
                    //Go through buffer and if packets are in window and pkt.sent = false => send it and toggle bool

                    if (rdt.IsSeqInRange(seqNum, srSendBase, (byte)(srSendBase + srWindowSize - 1)))
                    {
                        sendBucket.MarkAsAcked(seqNum);
                        OnDeliver?.Invoke(InvokeReason.Debug, "Received ACK: " + seqNum.ToString()
                                          + PrintSRDebugInfo());
                        if (seqNum == srSendBase)
                        {
                            //int i = 0;
                            //While packet is sent -> remove it from sendBucket, increment counter, add counter to srSendBase
                            while (sendBucket.IsSent(srSendBase) && sendBucket.IsAcked(srSendBase))
                            {
                                sendBucket.RemoveFromBucket(srSendBase);
                                srSendBase++;
                            }
                            //While packet in sendBucket is in new window && hasn't been sent, send it and toggle it's state
                            //E.g for each srSendBase to srSendBase + N -1, if is in sendBucket & is not sent, send it now
                            //As dictionary is not ordered, we loop over range srSendBase -> srSendBase + N - 1. Stopping early if key isn't in bucket.
                            for (byte i = srSendBase; rdt.IsSeqInRange(i, srSendBase, (byte)(srSendBase + srWindowSize - 1)); i++)
                            {
                                if (!sendBucket.ContainsKey(i))
                                {
                                    break;
                                }
                                socket.Send(sendBucket.GetDatagramBySeq(i));
                                sendBucket.MarkAsSent(i);
                                //srNextSeqNum++;
                            }
                            OnDeliver.Invoke(InvokeReason.Debug, "Sender window moved. " + PrintSRDebugInfo());
                        }
                    }
                }
                else
                {
                    if (rdt.IsSeqInRange(seqNum, (byte)(srRcvBase - srWindowSize), (byte)(srRcvBase + srWindowSize - 1)))
                    {
                        RdtSend(rdt.MakeAck(seqNum), true);
                        OnDeliver?.Invoke(InvokeReason.Debug, "Received Pkt: " + seqNum.ToString()
                                          + PrintSRDebugInfo());
                        if (rdt.IsSeqInRange(seqNum, srRcvBase, (byte)(srRcvBase + srWindowSize - 1)))
                        {
                            if (!rcvBucket.ContainsKey(seqNum))
                            {
                                rcvBucket.AddToBucket(datagram, seqNum);
                            }
                            else
                            {
                                OnDeliver.Invoke(InvokeReason.Debug, "Received duplicate: " + seqNum.ToString());
                            }

                            if (seqNum == srRcvBase)
                            {
                                /*Pass a Action delegate for handling method. Method chain removes from buffer,
                                 * handles packets, returns count of handled. Naming scheme I use is bad, I know :(*/
                                srRcvBase = (byte)(srRcvBase + ProcessValidBufferedSequence(srRcvBase,
                                                                                            DeliverDataSequenceToUpperLayer));
                                OnDeliver.Invoke(InvokeReason.Debug, "Receiver window moved. " + PrintSRDebugInfo());
                            }
                        }
                    }
                }
            }
            else
            {
                //This Kurose implementation will ignore corrupted packets and relies on timeout to recover
                //Alternative is to send SREPEAT-control message to request retransmission for seqnum-1 packet.

                OnDeliver?.Invoke(InvokeReason.Error, "Received corrupted");
            }
        }