Beispiel #1
0
    // 들어온 시퀀스 번호 : seq
    // seq > 0 또는 seq < -benchmark -> 처리안함.
    // seq < 0 또는 seq >  benchmark -> 처리함.
    public bool JudgeIncomePayload(RUDPPayload payload)
    {
        int distance = nextExpectIncomeSeqNum - payload.SequenceNumber;

        if (distance > 0 || distance < -InFlightPayload.benchmark)
        {
            if (distance > InFlightPayload.benchmark)
            {
                nextExpectIncomeSeqNum = payload.SequenceNumber;
                nextExpectIncomeSeqNum++;

                this.AddPendingAck(payload.SequenceNumber);
                return(true);
            }
            return(false);
        }
        else
        {
            nextExpectIncomeSeqNum = payload.SequenceNumber;
            nextExpectIncomeSeqNum++;

            this.AddPendingAck(payload.SequenceNumber);
            return(true);
        }
    }
    public void SendPayload(RUDPPayload payload)
    {
        if (flagDisconnect)
        {
            return;
        }

#if DEBUG //DEBUG 로 빌드될때 패킷 유실을 흉내내기 위해 Config에 정의된 확률에 따라 패킷을 보내지 않음.(Queue에 추가시키지않음)
        System.Random random = new System.Random();

        if (random.Next() % 100 < Config.PACKET_DROP_SIMULATION_RATIO)   //이런식으로 구현하면 실제로는 정의한 비율대로 동작안함..
        {
            return;                                                      //패킷을 많이 보내니까 그냥 편의상 이렇게 해둠.
                                                                         // Ack패킷 까지 드랍시키기 때문에 실제로 정한 확률 이상으로 드랍되게됨.(받아도 Ack를 제대로 못보내니까)
                                                                         // Ack가 실제 네트워크에선 드랍되기도 하기때문에 그냥 이대로 놔두기로함.
        }
#endif

        int count = 0;

        lock (sendPayloadQueueLock) {
            sendPayloadQueue.Enqueue(payload);
            count = sendPayloadQueue.Count;
        }

        if (count == 1)
        {
            StartSend();
        }
    }
    /// <summary>
    /// </summary>
    /// <param name="aleadyRemoteDisconnect">
    /// 이미 원격종단점의 연결이 끊겨있으면 해당 인자를 True,
    /// 상대방이 먼저 끊었을때 패킷보내는 작업 없이 소켓을 정리하기 위해 사용함</param>
    /// <param name="immediately">
    /// 현재 남은 패킷을 다 보내고 종료할거면 False 패킷을 모두 폐기하고 종료할거면 True
    /// </param>
    public void Disconnect(bool aleadyRemoteDisconnect, bool immediately)
    {
        if (aleadyRemoteDisconnect)
        {
            socket.Close();
            lock (this.sendPayloadQueueLock) {
                sendPayloadQueue.Clear();
            }
            return;
        }

        if (flagDisconnect)
        {
            return;
        }
        this.flagDisconnectImmediately = immediately;

        if (immediately)
        {
            lock (this.sendPayloadQueueLock) {
                this.sendPayloadQueue.Clear();
            }
        }

        RUDPPayload disconnectPayload = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DISCONNECT);

        disconnectPayload.Packet = new Packet(Packet.HEADER.RUDP, 8);
        this.SendPayload(disconnectPayload);
        this.flagDisconnect = true;
    }
    private void ThreadMainConnect()
    {
        while (true)
        {
            if (connectThreadAbortFlag)
            {
                connectThreadAbortFlag = false;
                break;
            }

            Array.Clear(recvBuffer, 0, recvBuffer.Length);

            int byteTransferred = 0;

            try
            {
                byteTransferred = socket.ReceiveFrom(recvBuffer, SocketFlags.None, ref remoteEndPoint);
            } catch (Exception e) {
                Debug.Log(e.GetType().Name + " " + e.Message + " " + e.StackTrace);
                OnConnectFail();
                ResetConnector();
                continue;
            }

            Queue <RUDPPayload> payloads = RUDPPayload.BytesToPayloads(recvBuffer, 0, byteTransferred);

            if (payloads.Count == 1)
            {
                RUDPPayload payload = payloads.Dequeue();

                if (payload != null)
                {
                    switch (payload.Tag)
                    {
                    case RUDPPayload.PAYLOAD_TAG.SYN:
                    {
                        ProcessSYN();
                        break;
                    }

                    case RUDPPayload.PAYLOAD_TAG.SYN_ACK:
                    {
                        ProcessSYN_ACK();
                        break;
                    }

                    case RUDPPayload.PAYLOAD_TAG.ACK:
                    {
                        ProcessACK();
                        break;
                    }
                    }
                }
            }
        }
    }
Beispiel #5
0
    private void SendAck(Packet p)
    {
        if (isDisable)
        {
            return;
        }

        RUDPPayload payload = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.ACK);

        payload.Packet = p;

        sender.SendPayload(payload);
    }
Beispiel #6
0
    public void SendRaw(Packet p)
    {
        if (isDisable)
        {
            return;
        }

        RUDPPayload payload = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.RAW);

        payload.Packet = p;

        sender.SendPayload(payload);
    }
Beispiel #7
0
    /// <summary>
    /// Payload에 Sequence번호를 쓰고 현재 시간을 sendingTime에 기록하고 Inflight패킷에 등록함.
    /// </summary>
    /// <param name="payload"></param>
    /// <returns></returns>
    public ushort PrepareToDeliver(RUDPPayload payload)
    {
        InFlightPayload p = new InFlightPayload();

        p.Payload = payload;

        lock (inflightPayloadsLock)
        {
            p.Payload.SequenceNumber = nextOutgoingSeqNum++;
            this.inflightPayloads.Enqueue(p);
            statistics.AllPayloadCount++;
        }
        return(payload.SequenceNumber);
    }
    private void OnReceive(object sender, SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            Queue <RUDPPayload> recvPayloads = RUDPPayload.BytesToPayloads(e.Buffer, e.Offset, e.BytesTransferred);

            this.OnReceivePayloads.Invoke(recvPayloads);

            this.StartReceive();
        }
        else
        {
            Debug.Log("패킷 수신에 문제가 생겼습니다. " + e.SocketError.ToString());
        }
    }
Beispiel #9
0
        public void TrackingModuleTest()
        {
            RUDPDeliverTrackingModule trackingModule = new RUDPDeliverTrackingModule();

            ushort seed          = 65520;
            ushort payloadsCount = 0;

            trackingModule.Reset(65520);

            for (ushort i = seed; i != 20; i++)
            {
                RUDPPayload newPayload = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY, 0);
                newPayload.Packet = this.emptyPacket;
                trackingModule.PrepareToDeliver(newPayload);
                payloadsCount++;
            }

            // 몇가지 Seq를 뺀 Ack를 만들어서 trackingModule에서 Ack를 처리하게 해야함
            // 그리고 결과를 처음 빠트린 Ack와 정상 ACk와 일치하는지 검증

            ushort halfPoint = seed;

            halfPoint += (ushort)(payloadsCount / 2);

            AckRange ackR = new AckRange(halfPoint, (ushort)(payloadsCount / 2));

            trackingModule.ProcessAckRange(ackR);

            ushort[] success = trackingModule.GetAndClearSuccessPayloadSeqNums();
            ushort[] fail    = trackingModule.GetAndClearLossPayloadSeqNums();

            Assert.IsTrue(ackR.AckCount == success.Length);
            Assert.IsTrue((payloadsCount - ackR.AckCount) == fail.Length);

            for (int i = 0; i < ackR.AckCount; i++)   //성공한 Ack
            {
                Assert.IsTrue((ackR.StartNum + i) == success[i]);
            }

            ushort start = seed;

            for (ushort i = 0; i < (payloadsCount - ackR.AckCount); i++)   //실패한 Ack
            {
                Assert.IsTrue((ushort)start == fail[i]);
                start++;
            }
        }
Beispiel #10
0
    /// <summary>
    /// 바이트 배열을 복수의 페이로드로 파싱
    /// </summary>
    /// <param name="bytes">변환할 바이트 배열</param>
    /// <param name="offset">오프셋</param>
    /// <param name="length">변환할 바이트의 총 길이</param>
    /// <returns></returns>
    public static Queue <RUDPPayload> BytesToPayloads(byte[] bytes, int offset, int length)
    {
        Queue <RUDPPayload> result = new Queue <RUDPPayload>(10);
        int cursor = 0;

        while ((length - cursor) >= (RUDPPayload.PAYLOAD_HEADER_SIZE + Packet.FIXED_AREA_SIZE))
        {
            RUDPPayload payload    = new RUDPPayload((PAYLOAD_TAG)bytes[cursor + offset], BitConverter.ToUInt16(bytes, cursor + offset + 1));
            int         packetSize = Packet.FIXED_AREA_SIZE + BitConverter.ToInt32(bytes, offset + RUDPPayload.PAYLOAD_HEADER_SIZE + cursor + sizeof(Packet.HEADER));
            Packet      packet     = Packet.BytesToPacket(bytes, packetSize, offset + RUDPPayload.PAYLOAD_HEADER_SIZE + cursor);
            payload.Packet = packet;
            cursor        += payload.Size;
            result.Enqueue(payload);
        }

        return(result);
    }
Beispiel #11
0
    public ushort SendDeliverNotify(Packet p)
    {
        if (isDisable)
        {
            throw new Exception("RUDPClientExpired");
        }

        RUDPPayload payload = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY);

        payload.Packet = p;

        ushort resultSeqNum = deliverTrackingModule.PrepareToDeliver(payload);

        sender.SendPayload(payload);;

        return(resultSeqNum);
    }
        public void RUDPPayloadTest()
        {
            RUDPPayload payload1 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.RAW, 20);
            RUDPPayload payload2 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.ACK, 21);
            RUDPPayload payload3 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY, 22);

            Packet test1 = new Packet(Packet.HEADER.RUDP);

            test1.Push(23);
            test1.Push("If you see this, you turn into great one.");
            Packet test2 = new Packet(Packet.HEADER.MESSAGE);

            test2.Push(34);
            test2.Push("I will not give up, my life is totally mine");

            // 아무 패킷이 안붙을때 붙는 빈 더미 패킷
            Packet test3 = new Packet(Packet.HEADER.RUDP, 8);

            payload1.Packet = test1;
            payload2.Packet = test2;
            payload3.Packet = test3;

            byte[] allbytes = new byte[payload1.Size + payload2.Size + payload3.Size];

            Buffer.BlockCopy(payload1.ToBytes(), 0, allbytes, 0, payload1.Size);
            Buffer.BlockCopy(payload2.ToBytes(), 0, allbytes, payload1.Size, payload2.Size);
            Buffer.BlockCopy(payload3.ToBytes(), 0, allbytes, payload1.Size + payload2.Size, payload3.Size);

            Queue <RUDPPayload> queue = RUDPPayload.BytesToPayloads(allbytes, 0, allbytes.Length);

            RUDPPayload popPayload1 = queue.Dequeue();
            RUDPPayload popPayload2 = queue.Dequeue();
            RUDPPayload popPayload3 = queue.Dequeue();

            Assert.IsTrue(popPayload3.PayloadHeader.SequenceEqual(payload3.PayloadHeader));
            Assert.IsTrue(payload3.Packet.Data.Take(payload3.Packet.SizeIncludedFixedArea).SequenceEqual(popPayload3.Packet.Data));

            Assert.IsTrue(popPayload2.PayloadHeader.SequenceEqual(payload2.PayloadHeader));
            Assert.IsTrue(payload2.Packet.Data.Take(payload2.Packet.SizeIncludedFixedArea).SequenceEqual(popPayload2.Packet.Data));

            Assert.IsTrue(popPayload1.PayloadHeader.SequenceEqual(payload1.PayloadHeader));
            Assert.IsTrue(payload1.Packet.Data.Take(payload1.Packet.SizeIncludedFixedArea).SequenceEqual(popPayload1.Packet.Data));
        }
Beispiel #13
0
    public void SendPendingAcks()
    {
        if (deliverConfirmModule.IsPendingAcksExist())
        {
            Queue <AckRange> acks = deliverConfirmModule.PopPendingAckRanges();

            var acksIter = acks.GetEnumerator();

            while (acksIter.MoveNext())
            {
                RUDPPayload acksPayload = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.ACK);
                Packet      acksPacket  = new Packet(Packet.HEADER.RUDP);

                acksPacket.Push(acksIter.Current.StartNum);
                acksPacket.Push(acksIter.Current.AckCount);
                acksPayload.Packet = acksPacket;
                this.SendAck(acksPacket);
                //Debug.Log(string.Format("Ack 보냄 StartNum : {0}, Count : {1}", acksIter.Current.StartNum, acksIter.Current.AckCount));
            }
        }
    }
Beispiel #14
0
        public void ConfirmModuleTest()
        {
            RUDPDeliverConfirmModule confirmModule = new RUDPDeliverConfirmModule();

            confirmModule.Reset(ushort.MaxValue - 3); // 시퀀스 번호 최대값에 근접시키기(오버플로우 테스트 위해)

            // 시퀀스 번호가 낮을때 False Return
            RUDPPayload payload1 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY, ushort.MaxValue - 4);

            payload1.Packet = emptyPacket;

            bool result = confirmModule.JudgeIncomePayload(payload1);

            Assert.IsTrue(result == false);

            // 시퀀스 번호가 같을때 True Return
            RUDPPayload payload2 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY, ushort.MaxValue - 3);

            payload2.Packet = emptyPacket;

            bool result2 = confirmModule.JudgeIncomePayload(payload2);

            Assert.IsTrue(result2 == true);

            //시퀀스 번호가 높을때 (위에 테스트때문에 현재 ConfirmModule의 다음예상시퀀스는 ushort.MaxValue-2 임
            RUDPPayload payload3 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY, ushort.MaxValue - 1);

            payload3.Packet = emptyPacket;

            bool result3 = confirmModule.JudgeIncomePayload(payload3);

            Assert.IsTrue(result3 == true);

            //시퀀스 번호 오버플로우 구간일때(true 리턴해야함)
            RUDPPayload payload4 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY, 200);
            RUDPPayload payload5 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY, 201);
            RUDPPayload payload6 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY, 202);
            RUDPPayload payload7 = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY, 203);

            payload4.Packet = emptyPacket;
            payload5.Packet = emptyPacket;
            payload6.Packet = emptyPacket;
            payload7.Packet = emptyPacket;

            bool result4 = confirmModule.JudgeIncomePayload(payload4);

            Assert.IsTrue(result4 == true);

            // 밑에 AckRange검사용
            confirmModule.JudgeIncomePayload(payload5);
            confirmModule.JudgeIncomePayload(payload6);
            confirmModule.JudgeIncomePayload(payload7);


            //AckRange 가 잘 나오는지 검사
            Queue <AckRange> acks = confirmModule.PopPendingAckRanges();

            AckRange ack1 = acks.Dequeue();

            Assert.IsTrue(ack1.StartNum == (ushort.MaxValue - 3) && ack1.AckCount == 1);

            AckRange ack2 = acks.Dequeue();

            Assert.IsTrue(ack2.StartNum == (ushort.MaxValue - 1) && ack2.AckCount == 1);

            AckRange ack3 = acks.Dequeue();

            Assert.IsTrue(ack3.StartNum == 200 && ack3.AckCount == 4);
        }