[英]Generate consecutive IPv4 addresses based on a given integer
/// <summary>
/// Create IP part of the client information payload.
/// </summary>
/// <param name="index">Index of the current client being generated.</param>
/// <returns>Simulated client IP address.</returns>
private string CreateClientIp(UInt32 index)
{
index = (index << 2) + 3;
return $"192.{(index >> 16) & 0xFF}.{(index >> 8) & 0xFF}.{index & 0xFF}";
}
下面的方法是從 192.0.0.3 開始生成 IP,增量為 3。我希望我的第一個地址是 192.0.0.2(以避免網絡地址以及通常用於 GW 的第一個地址),然后增加下一個地址由一個。 對此有何想法? 謝謝!
我認為最簡單的方法是使用 IPAddress 並操作用於創建它們的字節。 如果您需要以字符串形式返回的 IP 地址,請在返回的 IP 地址上使用 ToString()。
static void Main(string[] _)
{
var address = IPAddress.Parse("192.168.0.2");
foreach (var ip in GetTestAddresses(address, 300))
{
Console.WriteLine(ip);
}
}
public static IEnumerable<IPAddress> GetTestAddresses(IPAddress start, int count)
{
var bytes = start.GetAddressBytes();
for (int i = 0; i < count; ++i)
{
var part4 = bytes[^1];
var part3 = bytes[^2];
if (part4 < 255)
{
++part4;
}
else if (part3 < 255)
{
part4 = 0;
++part3;
}
else
{
break;
}
bytes[^1] = part4;
bytes[^2] = part3;
yield return new IPAddress(bytes);
}
}
最好的結果是使用本機 C#/.Net IPv4 結構。 不幸的是,.Net 沒有很好的原生 IPv4 工具,或者至少我不知道它們。 有System.Net.IPAddress
,但它試圖在同一個地方同時支持 IPv6 和 IPv4。 當一個簡單的 32 位值可以做到時,它迫使我們存儲 64 位加上一堆額外的標志。
如果做不到這一點,我們應該考慮uint
值而不是字符串,至少對於較低級別的數學內容。 我確信有一個 NuGet 庫會有所幫助,但這很簡單,我可以把它放在這個答案中。
我也認為這是使用一些有趣的 linq 技術(例如迭代器和自定義運算符)的好地方(或至少有趣)。 我們可以制作一個簡單的序列,從給定的起點返回uint
值並知道廣播地址:
public static uint MaskFromCidr(int cidr)
{
//cidr is the number of 1's at the start of the result
// So /24 is 11111111111111111111111100000000 is 255.255.255.0
return uint.MaxValue << (32-cidr);
}
public static bool CheckMask(uint IP, uint mask)
{
return (IP | mask) == uint.MaxValue;
}
public static bool CheckMask(uint IP, int cidr)
{
return CheckMask(IP, MaskFromCidr(cidr));
}
public static IEnumerable<uint> IPSequence(uint start_address, int cidr = 24)
{
uint mask = MaskFromCidr(cidr);
while (!CheckMask(start_address, mask))
{
yield return start_address;
start_address++;
}
}
然后添加一個 linq 運算符和一個格式化函數以進行良好的度量:
public static IEnumerable<T> EveryNth<T>(this IEnumerable<T> items, int n)
{
int i = 0;
foreach(var item in items)
{
if (i % n == 0)
{
yield return item;
i = 0; //for LARGE sequences, prevent int overflow
}
i++;
}
}
public static string DottedQuadFromUInt(uint IP)
{
return $"{(IP >> 24) & 0xFF}.{(IP >> 16) & 0xFF}.{(IP >> 8) & 0xFF}.{IP & 0xFF}";
}
然后像這樣把它們綁在一起:
uint start = 3232235522; //192.168.0.2 https://www.vultr.com/resources/ipv4-converter/?ip_address=192.168.0.2
var addresses = IPSequence(start).EvernNth(3).Take(2).Select(DottedQuadFromUInt);
foreach(var address in addresses)
{
Console.WriteLine(address);
}
請注意,我使用了192.168.0.2
而不是192.0.0.2
。 后者是public-routable ,你不應該將它用於內部地址。
看到它在這里工作:
這是避免地址以 255 結尾的更好代碼:
public class IncrementIP
{
byte[] array = new byte[4];
public IncrementIP(string IP)
{
array = IP.Split(new char[] { '.' }).Select(x => byte.Parse(x)).ToArray();
}
public string Increment()
{
int lsb = array[3] + 3;
if (lsb <= 254)
{
array[3] = (byte)lsb;
}
else
{
array[3] = 2;
for (int i = 2; i >= 0; i--)
{
if (array[i] == 254)
{
array[i] = 0;
}
else
{
array[i] += 1;
break;
}
}
}
return string.Join(".", array);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.