示例#1
0
 public void EnqueueSegment(Segment segment)
 {
     if (!this.IsClosed)
     {
         this.RecievedSegmentQueue.Enqueue(segment);
         this.QueueWaitEvent.Set();
     }
 }
示例#2
0
            protected override void OnSendSegment(Segment segment)
            {
                Console.WriteLine("Send Segment [{0}]", segment.ToString());

                using (var ws = new MemoryStream())
                {
                    segment.WriteBytes(ws);
                    var bytes = ws.GetBuffer();
                    var length = ws.Position;
                    this.Udp.Send(bytes, (int)length, this.RemoteEp);
                }
            }
示例#3
0
        /// <summary>
        /// セグメントの送信と返事待ちセグメントキューへの登録.
        /// </summary>
        /// <param name="segment"></param>
        private void SendAndQueueSegment(Segment segment)
        {
            while (this.UnAckedSentSegmentList.Count >= SendQueueSize
                || this.Counter.GetOutStandingSegmentCount() >= this.Parameter.MaxNumberOfOutStandingSegs)
            {
                this.VacantUnAckedSentSegListWait.WaitOne();
            }

            // TODO
            // UnAckedSentSegmentListの数で代用できないか?
            // 返事待ちセグメントの数を増やす.
            this.Counter.IncrementOutStandingSegmentCount();

            // 返事のない送信済み(返事待ち)セグメントリストに登録.
            this.UnAckedSentSegmentList.Add(segment);

            // UnAckedSentSegmentListが空でなくなったので待機イベントに通知.
            this.NotEmptyUnAckedSentSegListWait.Set();

            // TODO
            // 返事のない送信済み(返事待ち)セグメントについて再送するためのスレッドを起こす.

            // セグメント送信.
            SendSegment(segment);

            // データセグメントの場合はリスナーにパケットを送信したことを通知する.
            if (segment is DataSegment)
            {
                OnSentPacket();
            }
        }
示例#4
0
        /// <summary>
        /// セグメント送信.
        /// </summary>
        /// <param name="segment"></param>
        private void SendSegment(Segment segment)
        {
            // ACK(返事)の抱き合わせ設定
            if (segment is DataSegment
                || segment is ResetSegment
                || segment is FinishSegment
                || segment is NullSegment)
            {
                // 受信したけど返事をしていないセグメントの有無を確認.
                if (this.UnAckedRecievedSegmentList.Count > 0)
                {
                    // 返事待ちセグメントが存在すれば、ACK(返事)フラグをセグメントに設定する.
                    // どの番号に対応するACK(返事)なのかをセット.
                    segment.SetAcknowledgedNumber(this.Counter.GetLastInSequenceNumber());
                }
            }

            if (segment is DataSegment
                || segment is ResetSegment
                || segment is FinishSegment)
            {
                // TODO
                // Reset null segment timer
            }

            // 送信.
            OnSendSegment(segment);
        }
示例#5
0
        /// <summary>
        /// セグメントを再送.
        /// </summary>
        /// <param name="segment"></param>
        private void RetransmitSegment(Segment segment)
        {
            // 再送回数を増やす.
            segment.RetryCount++;

            if (this.Parameter.MaxRetransmission != 0
                && segment.RetryCount > this.Parameter.MaxRetransmission)
            {
                // TODO
                // 最大再送回数を超えた場合は接続が失敗していることにする.
                return;
            }

            Console.Write("RetransmitSegment --- ");
            SendSegment(segment);
        }
示例#6
0
        /// <summary>
        /// 受信した返事を返す.
        /// </summary>
        /// <param name="segment">返事をする対象のセグメント</param>
        private void SendAcknowledgement(Segment segment)
        {
            lock(this.RecieveQueueLocker)
            {
                // 受信したけど out-of-sequence 状態のセグメントがある場合.
                if (this.OutSequenceSegmentList.Count > 0)
                {
                    SendExtendAcknowledgement();
                    return;
                }

                SendSingleAcknowledgement(segment);
            }
        }
示例#7
0
        /// <summary>
        /// 受信したセグメントを処理.
        /// </summary>
        /// <param name="segment"></param>
        private void HandleSegment(Segment segment)
        {
            // リセットセグメントがきたので通信をリセットする.
            if (segment is ResetSegment)
            {
                // TODO
            }

            // これ以上なにも送られてこないことが通知されてきた.
            if (segment is FinishSegment)
            {
                switch((State)this.CurState)
                {
                    case State.SYN_SENT:
                        // 同期セグメント送信状態の場合は、返事待ちしているところ(connect)を解除して先に進むようにする.
                        this.ConnectEvent.Set();
                        break;
                    case State.CLOSED:
                        // すでに終了しているので何もしない.
                        break;
                    default:
                        this.CurState.Store(State.WILL_CLOSE);
                        break;
                }
            }

            // シーケンス番号が正しいかどうか.
            bool isInSequence = false;

            lock (this.RecieveQueueLocker)
            {
                // 期待するシーケンス番号.
                var nextSeqNumber = NextSequenceNumber(Counter.GetLastInSequenceNumber());

                if (CompareSequenceNumbers(segment.SequenceNumber, Counter.GetLastInSequenceNumber()) >= 0)
                {
                    // 送信したものと同じもの or 番号が小さいものがきた(すでに届いているものがきた)ので無視する.
                }
                else if (CompareSequenceNumbers(segment.SequenceNumber, nextSeqNumber) == 0)
                {
                    // 期待する番号がきた.
                    isInSequence = true;

                    if (this.InSequenceSegmentList.Count + this.OutSequenceSegmentList.Count < MaxRecvListSize)
                    {
                        // キューに余裕がある.

                        // シーケンス番号を更新.
                        this.Counter.SetLastInSequenceNumber(segment.SequenceNumber);

                        if (segment is DataSegment
                            || segment is ResetSegment
                            || segment is FinishSegment)
                        {
                            // read で読み込むセグメントはリストに登録.
                            this.InSequenceSegmentList.Add(segment);
                            InSequenceSegWait.Set();
                        }

            #if false
                        // 順番通りにデータが来たことを通知.
                        if (segment is DataSegment)
                        {
                            OnRecivedPacketInOrder(segment as DataSegment);
                        }
            #endif

                        // シーケンス番号が変わったので、out-of-sequenceリストから正しい順序のものを InSequenceSegmentQueue に移す.
                        UpdateOutSequeceQueue();
                    }
                    else
                    {
                        // リストがいっぱいなので、何もしない.
                    }
                }
                else
                {
                    // シーケンス番号が順番がずれた(パケット順序がおかしくなった)ので、out-of-sequenceリストに登録する.

                    if (this.InSequenceSegmentList.Count + this.OutSequenceSegmentList.Count < MaxRecvListSize)
                    {
                        bool added = false;

                        for (int i = 0; i < this.OutSequenceSegmentList.Count; i++)
                        {
                            var s = this.OutSequenceSegmentList.Values[i];

                            if (CompareSequenceNumbers(segment.SequenceNumber, s.SequenceNumber) == 0)
                            {
                                // 登録済み.
                                added = true;
                                break;
                            }
                        }

                        if (!added)
                        {
                            // 未登録なので、登録する.
                            this.OutSequenceSegmentList.Add(segment.SequenceNumber, segment);
                        }

            #if false
                        // 順序がずれたパケットを受けたことを通知する.
                        if (segment is DataSegment)
                        {
                            OnRecivedPacketOutOfOrder(segment as DataSegment);
                        }
            #endif
                    }
                }

                if (isInSequence && (segment is DataSegment
                                    || segment is NullSegment
                                    || segment is FinishSegment)
                    )
                {
                    // 受信した応答を返す.
                    SendAcknowledgement(segment);
                }
                else if (this.OutSequenceSegmentList.Count > this.Parameter.MaxOutOfSequence)
                //else if (this.OutSequenceSegmentList.Count > 0)
                {
                    // out-of-sequenceセグメントの数が許容最大値を超えた.
                    SendExtendAcknowledgement();
                }
                else if (this.UnAckedRecievedSegmentList.Count > this.Parameter.MaxCumulativeAck)
                {
                    // 受信したけど確認応答を送っていないセグメントの数が許容最大値を超えた.
                    SendSingleAcknowledgement(segment);
                }
                else
                {
                    // TODO
                    // 上記以外の場合は、定期的にACKセグメント送る.
                }
            }
        }
示例#8
0
        private void CheckAndGetAck(Segment segment)
        {
            int ackNumber = segment.GetAcknowledgedNumber();

            if (ackNumber < 0)
            {
                return;
            }

            if (this.CurState == State.SYN_RECV)
            {
                OpenConnection();

                // 接続要求を受信した返事に対する返事なので、接続を開く.
                this.CurState.Store(State.ESTABLISHED);
            }

            this.UnAckedSentSegmentList.ForeachWithRemoving(
                (Segment s) =>
                {
                    return (CompareSequenceNumbers(s.SequenceNumber, ackNumber) <= 0);
                });

            this.VacantUnAckedSentSegListWait.Set();
        }
示例#9
0
        /// <summary>
        /// セグメント送信実装.
        /// </summary>
        /// <param name="segment"></param>
        protected virtual void OnSendSegment(Segment segment)
        {
            // 疑似パケット順番入れ替え

            if (!this.IsConnected || segment is AcknowledgementSegment)
            {
                using (var ws = new MemoryStream())
                {
                    Console.WriteLine("Send Segment [{0}]", segment.ToString());
                    segment.WriteBytes(ws);
                    var bytes = ws.GetBuffer();
                    var length = ws.Position;
                    this.Udp.Send(bytes, (int)length);
                }
            }
            else
            {
                if (isValid)
                {
                    using (var ws = new MemoryStream())
                    {
                        {
                            Console.WriteLine("Send Segment [{0}]", segment.ToString());
                            segment.WriteBytes(ws);
                            var bytes = ws.GetBuffer();
                            var length = ws.Position;
                            this.Udp.Send(bytes, (int)length);
                        }
                    }

                    using (var ws = new MemoryStream())
                    {
                        if (TempQueue.Count > 0)
                        {
                            var s = TempQueue.Dequeue();
                            Console.WriteLine("Send Segment [{0}]", s.ToString());
                            s.WriteBytes(ws);
                            var bytes = ws.GetBuffer();
                            var length = ws.Position;
                            this.Udp.Send(bytes, (int)length);
                        }
                    }
                }
                else
                {
                    isValid = true;
                    TempQueue.Enqueue(segment);
                }
            }
        }
示例#10
0
        /// <summary>
        /// セグメント送信実装.
        /// </summary>
        /// <param name="segment"></param>
        protected virtual void OnSendSegment(Segment segment)
        {
            // 疑似パケットロス発生

            if (isValid)
            {
                using (var ws = new MemoryStream())
                {
                    segment.WriteBytes(ws);
                    var bytes = ws.GetBuffer();
                    var length = ws.Position;
                    this.Udp.Send(bytes, (int)length);
                }
            }
            else
            {
                // TODO
                isValid = true;
            }
        }
示例#11
0
        /// <summary>
        /// 受信した返事を返す.
        /// </summary>
        /// <param name="segment">返事をする対象のセグメント</param>
        private void SendSingleAcknowledgement(Segment segment)
        {
            // 受信したけど返信していないセグメントの数が 0 のときは何もしない.
            if (this.UnAckedRecievedSegmentList.Count == 0)
            {
                return;
            }

            #if false
            var lastInSequence = this.Counter.GetLastInSequenceNumber();

            var sendSegment = new AcknowledgementSegment(
                NextSequenceNumber(lastInSequence),
                lastInSequence);
            #else
            var sendSegment = new AcknowledgementSegment(
                NextSequenceNumber(segment.SequenceNumber),
                segment.SequenceNumber);
            #endif

            // 送信.
            SendSegment(sendSegment);

            if (segment != null)
            {
                // NOTE
                // 順番が入れ替わった場合もあるのでここでシーケンス番号チェックはできない

                // 受信したが確認応答を送っていないセグメントのリストから削除.
                this.UnAckedRecievedSegmentList.Remove(segment);
            }
        }