[C#]簡易的Backoff window實現類別
在無線網路的領域中,若是節點間要進行傳輸,會試圖嚐試發送RTS訊號,當接收端收到且允許傳送時,接收端會發送CTS訊號,傳送端就會知道可以進行傳送的動作。但若是傳送端發送了RTS後過段時間沒收到CTS訊號,代表訊號被碰撞掉了,這時會挑選個backoff值,決定要多久後再重試傳輸。這邊的backoff值會隨著碰撞而變大backoff值的區間,也就是無線網路領域所謂的Backoff window機制。
這樣的機制很簡單,但卻能分散碰撞,並將重試的時間調在適當的區間。這樣的機制一樣可以拿來套用在我們一般程式的開發,就像有時後訂Delay time時不知道該設多少,訂多訂少都會有不好的影響,那倒不如導入這樣的一個機制讓它自我調適。
這邊筆者憑著印象刻了一個簡單的BackOff類別。
程式碼如下:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
namespace ConsoleApplication12
{
public class BackOff
{
#region Var
private int _level;
private Random _random;
#endregion
#region Private Property
private ReadOnlyCollection<int> m_BackOffWindows { get; set; }
private Random m_Random
{
get
{
if (_random == null)
_random = new Random(Guid.NewGuid().GetHashCode());
return _random;
}
}
#endregion
#region Public Property
/// <summary>
/// Gets or sets the level.
/// </summary>
/// <value>The level.</value>
public int Level
{
get
{
return _level;
}
set
{
if (value <= 0)
throw new Exception("Level value must be bigger than zero!");
if (value > m_BackOffWindows.Count)
throw new Exception("Level value incorrect!");
_level = value;
}
}
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="BackOff"/> class.
/// </summary>
/// <param name="backOffWindows">The back off windows.</param>
public BackOff(params int[] backOffWindows)
{
CheckBackOffWindows(backOffWindows);
this.m_BackOffWindows = new ReadOnlyCollection<int>(backOffWindows.ToList());
ResetLevel();
}
#endregion
#region Private Method
/// <summary>
/// Checks the back off windows.
/// </summary>
/// <param name="backOffWindows">The back off windows.</param>
private void CheckBackOffWindows(params int[] backOffWindows)
{
if (backOffWindows == null)
throw new ArgumentNullException("backOffWindows");
if (backOffWindows.Length == 0)
throw new ArgumentException("backOffWindows must contains elements!");
if (backOffWindows.First() <= 0)
throw new ArgumentOutOfRangeException("First backOffWindow must bigger than zero!");
var minValue = -1;
foreach (var backOffWindow in backOffWindows)
{
if (backOffWindow < 0)
throw new ArgumentOutOfRangeException("backOffWindows must bigger than zero!");
if (minValue > backOffWindow)
throw new ArgumentOutOfRangeException("backOffWindows must order by increase!");
if (minValue == backOffWindow)
throw new ArgumentOutOfRangeException("Can't contains duplicated elements!");
minValue = backOffWindow;
}
}
#endregion
#region Public Method
/// <summary>
/// Increases the level.
/// </summary>
/// <returns></returns>
public Boolean IncreaseLevel()
{
if (Level >= m_BackOffWindows.Count)
return false;
Level += 1;
return true;
}
/// <summary>
/// Decreases the level.
/// </summary>
/// <returns></returns>
public Boolean DecreaseLevel()
{
if (Level <= 1)
return false;
Level -= 1;
return true;
}
public void ResetLevel()
{
Level = 1;
}
/// <summary>
/// Gets the next value.
/// </summary>
/// <returns></returns>
public int NextValue()
{
var minValue = (Level == 1) ? 0 : m_BackOffWindows[Level - 2];
var maxValue = m_BackOffWindows[Level - 1];
return m_Random.Next(minValue, maxValue);
}
#endregion
}
}
實際使用時只要建立物件實體,並帶入backoff window的區間值,透過NextValue取得backoff值就可以了,若是碰撞則呼叫IncreaseLevel去將區間上調。
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication12
{
class Program
{
static void Main(string[] args)
{
BackOff backoff = new BackOff(16,32,64);
Console.WriteLine("Level1...");
Console.WriteLine(backoff.NextValue().ToString());
Console.WriteLine(backoff.NextValue().ToString());
Console.WriteLine(backoff.NextValue().ToString());
Console.WriteLine(new string('=', 50));
backoff.IncreaseLevel();
Console.WriteLine("Level2...");
Console.WriteLine(backoff.NextValue().ToString());
Console.WriteLine(backoff.NextValue().ToString());
Console.WriteLine(backoff.NextValue().ToString());
Console.WriteLine(new string('=', 50));
backoff.IncreaseLevel();
Console.WriteLine("Level3...");
Console.WriteLine(backoff.NextValue().ToString());
Console.WriteLine(backoff.NextValue().ToString());
Console.WriteLine(backoff.NextValue().ToString());
Console.WriteLine(new string('=', 50));
}
}
}