// 들어온 시퀀스 번호 : 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; } } } } } }
private void SendAck(Packet p) { if (isDisable) { return; } RUDPPayload payload = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.ACK); payload.Packet = p; sender.SendPayload(payload); }
public void SendRaw(Packet p) { if (isDisable) { return; } RUDPPayload payload = new RUDPPayload(RUDPPayload.PAYLOAD_TAG.RAW); payload.Packet = p; sender.SendPayload(payload); }
/// <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()); } }
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++; } }
/// <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); }
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)); }
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)); } } }
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); }