⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sackwindow.cs

📁 rudp可靠保障得udp传输
💻 CS
字号:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Helper.Net.RUDP
{
	#region SACKSlot

	internal sealed class SACKSlot
	{
		internal int StartPacketId;
		internal int EndPacketId;

		// To avoid to resend several times the same ACK
		internal int ACKsCount = 1;

		internal SACKSlot(int startPacketId, int endPacketId)
		{
			StartPacketId = startPacketId;
			EndPacketId = endPacketId;
		}

		internal SACKSlot Clone()
		{
			return new SACKSlot(StartPacketId, EndPacketId);
		}
	}

	#endregion

	sealed internal class SACKWindow
	{

		#region Variables

		private List<SACKSlot> _slots = new List<SACKSlot>();
		private int _acksCount = 0;

		#endregion

		#region Constructor

		internal SACKWindow()
		{
			_slots.Add(new SACKSlot(-1, -1));
		}

		#endregion

		#region OnReceivePacket

		internal void OnReceivePacket(int packetId)
		{
			RUDPStack.Trace("SACK OnReceivePacket:" + packetId);

			Monitor.Enter(this);
			try
			{
				SACKSlot slot;
				SACKSlot newSlot;
				for (int index = 0; index < _slots.Count; index++)
				{
					slot = _slots[index];

					//-- Already in the slot
					if (packetId >= slot.StartPacketId && packetId <= slot.EndPacketId)
					{
						slot.ACKsCount++;
						return;
					}

					//-- Grow the slot
					if (slot.EndPacketId + 1 == packetId)
					{
						slot.EndPacketId++;
						slot.ACKsCount++;

						// First packet
						if (slot.StartPacketId < 0)
							slot.StartPacketId = 0;

						// Merge with next
						if ((index + 1) < _slots.Count && (slot.EndPacketId + 1) == _slots[index + 1].StartPacketId)
						{
							index++;
							slot.EndPacketId = _slots[index].EndPacketId;

							_slots.RemoveAt(index);
						}

						return;
					}

					//-- Before this slot (and then after previous one !)
					if (packetId < slot.StartPacketId)
					{
						if (packetId == slot.StartPacketId - 1)
						{
							slot.StartPacketId--;
							slot.ACKsCount++;
						}
						else
						{
							newSlot = new SACKSlot(packetId, packetId);
							_slots.Insert(index, newSlot);
						}

						return;
					}
				}

				//-- New slot at the end
				newSlot = new SACKSlot(packetId, packetId);
				_slots.Add(newSlot);
			}
			finally
			{
				Monitor.Exit(this);
				Interlocked.Increment(ref _acksCount);
			}
		}

		#endregion

		#region PrepareACKList

		/// <summary>
		/// Used when "resending" or sending queued "ACKs"
		/// </summary>
		internal List<SACKSlot> PrepareACKList()
		{
			List<SACKSlot> list = new List<SACKSlot>();

			lock (this)
			{
				//---- Add all the slots, except the first one
				for (int index = 1; index < _slots.Count; index++)
				{
					SACKSlot slot = _slots[index];
					if (slot.ACKsCount > 0)
					{
						slot.ACKsCount = 0;
						list.Add(slot.Clone());
					}
				}
				
				//---- Add the first slot
				// Useful when some ACKs are loosed
				if (_slots[0].StartPacketId > -1)
					if (list.Count > 1 || _slots[0].ACKsCount > 0)
					{
						_slots[0].ACKsCount = 0;
						list.Insert(0, _slots[0].Clone());
					}
			}

			Interlocked.Exchange(ref _acksCount, 0);
			return list;
		}

		#endregion

		#region ACKCount

		/// <summary>
		/// Calculate the number of ACKs to send.
		/// </summary>
		internal int ACKCount
		{
			get
			{
				return _acksCount;
			}
		}

		#endregion

		#region GetSLACKSlots

		/// <summary>
		/// Used when sending a packet.
		/// </summary>
		internal void GetSLACKSlots(out SACKSlot slot1, out SACKSlot slot2, out SACKSlot slot3, out SACKSlot slot4)
		{
			slot1 = null;
			slot2 = null;
			slot3 = null;
			slot4 = null;

			lock (this)
			{
				if (_slots[0].StartPacketId < 0)
					return;

				//---- Useful when some ACKs are loosed
				slot1 = _slots[0].Clone();
				if (_slots[0].ACKsCount > 0)
					Interlocked.Decrement(ref _acksCount);

				//---- Add all the slots
				for (int index = 1; index < _slots.Count; index++)
				{
					SACKSlot slot = _slots[index];
					if (slot.ACKsCount > 0)
					{
						slot.ACKsCount = 0;
						if (slot2 == null)
							slot2 = slot.Clone();
						else if (slot3 == null)
							slot3 = slot.Clone();
						else if (slot4 == null)
						{
							slot4 = slot.Clone();
							Interlocked.Decrement(ref _acksCount);
							return;
						}
						Interlocked.Decrement(ref _acksCount);
					}
				}
			}
		}

		#endregion

	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -