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++; } }
private void OnReceivePayloads(Queue <RUDPPayload> payloads) { var iter = payloads.GetEnumerator(); while (iter.MoveNext()) { if (iter.Current.Packet != null) { switch (iter.Current.Tag) { case RUDPPayload.PAYLOAD_TAG.RAW: { OnPacketReceive(iter.Current.Packet); break; } case RUDPPayload.PAYLOAD_TAG.DELIVERY_NOFIFY: { //Debug.Log(string.Format("DeliverNotify 패킷 받음 {0}", iter.Current.SequenceNumber)); if (this.deliverConfirmModule.JudgeIncomePayload(iter.Current)) { OnPacketReceive(iter.Current.Packet); } break; } case RUDPPayload.PAYLOAD_TAG.ACK: { AckRange currentAck = new AckRange(0, iter.Current.Packet.Pop_UInt16()); currentAck.StartNum = iter.Current.Packet.Pop_UInt16(); //Debug.Log(string.Format("Ack 받음 StartNum : {0}, Count : {1}", currentAck.StartNum, currentAck.AckCount)); deliverTrackingModule.ProcessAckRange(currentAck); break; } case RUDPPayload.PAYLOAD_TAG.DISCONNECT: { isDisable = true; this.receiver.Disconnect(); this.sender.Disconnect(true, true); OnDisconnect.Invoke(); break; } } } } }
// AckRange 만큼의 Ack신호를 처리함. 주의점 : 절대로 타임아웃 패킷 정리와 동시에 수행되어서는 안됨. public void ProcessAckRange(AckRange range) { ushort currentInflightSeqNum = 0; int distance = 0; lock (inflightPayloadsLock) { currentInflightSeqNum = this.inflightPayloads.Peek().Payload.SequenceNumber; distance = currentInflightSeqNum - range.StartNum; } if (distance == 0) // 0이면 현재 inflight와 ack가 일치하는것임 { for (int i = 0; i < range.AckCount; i++) { ushort seq = 0; lock (inflightPayloadsLock) { seq = inflightPayloads.Dequeue().Payload.SequenceNumber; } statistics.SuccessPayloadCount++; lock (this.successPayloadSeqNumsLock) { this.successPayloadSeqNums.Enqueue(seq); } } } else if (distance > 0 || distance < -InFlightPayload.benchmark) { // Ack가 현재 Inflight보다 작음. 처리하지 않음 if (distance > InFlightPayload.benchmark) { // 오버플로우 구간인지 검사하고 오버플로우 구간이면 처리하도록 함. // ack값이 기대보다 큼 중간에 패킷이 손실된것으로 판단, ack값 이전까지의 패킷을 손실로 처리 ushort currentSeq = 0; lock (this.inflightPayloadsLock) { currentSeq = this.inflightPayloads.Peek().Payload.SequenceNumber; } while (currentSeq != range.StartNum) { lock (inflightPayloadsLock) { lock (this.lossPayloadSeqNumsLock) { this.lossPayloadSeqNums.Enqueue(inflightPayloads.Dequeue().Payload.SequenceNumber); } } statistics.FailedPayloadCount++; currentSeq++; } // ack에 해당하는 패킷들을 전송 성공처리 시켜줘야함. for (int i = 0; i < range.AckCount; i++) { ushort seq = 0; lock (inflightPayloadsLock) { seq = inflightPayloads.Dequeue().Payload.SequenceNumber; } statistics.SuccessPayloadCount++; lock (this.successPayloadSeqNumsLock) { this.successPayloadSeqNums.Enqueue(seq); } } } else //오버플로우도 아니니까 현재 Inflight보다 작은 것으로 판단됨, 처리하지않도록함. // ack신호를 무시하되, range 내에 무시해선 안될 ack가있는지 확인 { ushort end = range.StartNum; end += range.AckCount; for (ushort currentAck = range.StartNum; currentAck != end; currentAck++) { lock (inflightPayloadsLock) { if (currentAck == this.inflightPayloads.Peek().Payload.SequenceNumber) { lock (this.successPayloadSeqNumsLock) { this.successPayloadSeqNums.Enqueue(this.inflightPayloads.Dequeue().Payload.SequenceNumber); } statistics.SuccessPayloadCount++; } } } } } else { // ack값이 기대보다 큼 중간에 패킷이 손실된것으로 판단, ack값 이전까지의 패킷을 손실로 처리 ushort currentSeq = 0; lock (this.inflightPayloadsLock) { currentSeq = this.inflightPayloads.Peek().Payload.SequenceNumber; } while (currentSeq != range.StartNum) { lock (inflightPayloadsLock) { lock (this.lossPayloadSeqNumsLock) { this.lossPayloadSeqNums.Enqueue(inflightPayloads.Dequeue().Payload.SequenceNumber); } } statistics.FailedPayloadCount++; currentSeq++; } // ack에 해당하는 패킷들을 전송 성공처리 시켜줘야함. for (int i = 0; i < range.AckCount; i++) { ushort seq = 0; lock (inflightPayloadsLock) { seq = inflightPayloads.Dequeue().Payload.SequenceNumber; } statistics.SuccessPayloadCount++; lock (this.successPayloadSeqNumsLock) { this.successPayloadSeqNums.Enqueue(seq); } } } }
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); }