Sie können 10x-100x schneller erhalten, je nachdem, wie Sie mit ungültiger Netzmaske umgehen möchten, siehe - c code for valid netmask und https://superuser.com/questions/601252/is-225-225-225-128-a-valid-subnet-mask. Hier ist mein Benchmark-Ergebnis (wo Phantasie ist Ihr ursprünglicher Vorschlag, habe ich auch aus Neugier mit konstanter Zeit Ausführung experimentiert).
Lange Rede kurzer Sinn: arbeite in binär, benutze Konstanten, rolle deine Schleifen aus. Die Ultra Version könnte die beste sein. Bei ungültiger Netzmaske wird der nächste Wert zurückgegeben, der valid netmask enthält.
Wie wäre es nun mit IPv6? Wir haben vielleicht zu früh optimiert ... Ich hoffe niemand wagt es, die alte Netzmaskennotation für IPv6 zu verwenden. Es sollte vergessen werden.
11111111.11111111.11111111.11111111 (255.255.255.255)
{ ns = 625,574, cidrnet = 32, method = MaskToCIDR_Fancy }
{ ns = 61,136, cidrnet = 32, method = MaskToCIDR_Fast }
{ ns = 72,039, cidrnet = 32, method = MaskToCIDR_Constant }
{ ns = 4,710, cidrnet = 32, method = MaskToCIDR_Ultra }
{ ns = 14,250, cidrnet = 32, method = MaskToCIDR_ConstantUltra }
{ ns = 8,683, cidrnet = 32, method = MaskToCIDR_Mambo }
{ ns = 7,337, cidrnet = 32, method = MaskToCIDR_PerByte }
{ ns = 37,883, cidrnet = 32, method = MaskToCIDR_BTree }
{ ns = 2,127, cidrnet = 0, method = MaskToCIDR_Empty }
11111111.11111111.11111111.00000000 (255.255.255.0)
{ ns = 486,026, cidrnet = 24, method = MaskToCIDR_Fancy }
{ ns = 47,369, cidrnet = 24, method = MaskToCIDR_Fast }
{ ns = 69,921, cidrnet = 24, method = MaskToCIDR_Constant }
{ ns = 4,835, cidrnet = 24, method = MaskToCIDR_Ultra }
{ ns = 14,079, cidrnet = 24, method = MaskToCIDR_ConstantUltra }
{ ns = 6,663, cidrnet = 24, method = MaskToCIDR_Mambo }
{ ns = 7,336, cidrnet = 24, method = MaskToCIDR_PerByte }
{ ns = 24,911, cidrnet = 24, method = MaskToCIDR_BTree }
{ ns = 2,116, cidrnet = 0, method = MaskToCIDR_Empty }
11111111.11111111.11111110.00000000 (255.255.254.0)
{ ns = 482,456, cidrnet = 23, method = MaskToCIDR_Fancy }
{ ns = 45,700, cidrnet = 23, method = MaskToCIDR_Fast }
{ ns = 68,930, cidrnet = 23, method = MaskToCIDR_Constant }
{ ns = 4,791, cidrnet = 23, method = MaskToCIDR_Ultra }
{ ns = 14,036, cidrnet = 23, method = MaskToCIDR_ConstantUltra }
{ ns = 6,951, cidrnet = 23, method = MaskToCIDR_Mambo }
{ ns = 7,377, cidrnet = 23, method = MaskToCIDR_PerByte }
{ ns = 36,027, cidrnet = 23, method = MaskToCIDR_BTree }
{ ns = 2,115, cidrnet = 0, method = MaskToCIDR_Empty }
11111111.11111111.00000000.00000000 (255.255.0.0)
{ ns = 347,425, cidrnet = 16, method = MaskToCIDR_Fancy }
{ ns = 34,460, cidrnet = 16, method = MaskToCIDR_Fast }
{ ns = 67,445, cidrnet = 16, method = MaskToCIDR_Constant }
{ ns = 4,942, cidrnet = 16, method = MaskToCIDR_Ultra }
{ ns = 15,363, cidrnet = 16, method = MaskToCIDR_ConstantUltra }
{ ns = 6,164, cidrnet = 16, method = MaskToCIDR_Mambo }
{ ns = 7,929, cidrnet = 16, method = MaskToCIDR_PerByte }
{ ns = 22,312, cidrnet = 16, method = MaskToCIDR_BTree }
{ ns = 2,116, cidrnet = 0, method = MaskToCIDR_Empty }
11111111.00000000.00000000.00000000 (255.0.0.0)
{ ns = 198,180, cidrnet = 8, method = MaskToCIDR_Fancy }
{ ns = 20,683, cidrnet = 8, method = MaskToCIDR_Fast }
{ ns = 64,785, cidrnet = 8, method = MaskToCIDR_Constant }
{ ns = 5,138, cidrnet = 8, method = MaskToCIDR_Ultra }
{ ns = 14,058, cidrnet = 8, method = MaskToCIDR_ConstantUltra }
{ ns = 6,734, cidrnet = 8, method = MaskToCIDR_Mambo }
{ ns = 8,572, cidrnet = 8, method = MaskToCIDR_PerByte }
{ ns = 37,483, cidrnet = 8, method = MaskToCIDR_BTree }
{ ns = 2,253, cidrnet = 0, method = MaskToCIDR_Empty }
10000000.00000000.00000000.00000000 (128.0.0.0)
{ ns = 198,620, cidrnet = 1, method = MaskToCIDR_Fancy }
{ ns = 7,855, cidrnet = 1, method = MaskToCIDR_Fast }
{ ns = 62,570, cidrnet = 1, method = MaskToCIDR_Constant }
{ ns = 6,317, cidrnet = 1, method = MaskToCIDR_Ultra }
{ ns = 14,145, cidrnet = 1, method = MaskToCIDR_ConstantUltra }
{ ns = 6,399, cidrnet = 1, method = MaskToCIDR_Mambo }
{ ns = 7,413, cidrnet = 1, method = MaskToCIDR_PerByte }
{ ns = 33,861, cidrnet = 1, method = MaskToCIDR_BTree }
{ ns = 2,117, cidrnet = 0, method = MaskToCIDR_Empty }
00000000.00000000.00000000.00000000 (0.0.0.0)
{ ns = 83,629, cidrnet = 0, method = MaskToCIDR_Fancy }
{ ns = 7,348, cidrnet = 0, method = MaskToCIDR_Fast }
{ ns = 63,320, cidrnet = 0, method = MaskToCIDR_Constant }
{ ns = 4,639, cidrnet = 0, method = MaskToCIDR_Ultra }
{ ns = 14,284, cidrnet = 0, method = MaskToCIDR_ConstantUltra }
{ ns = 5,438, cidrnet = 0, method = MaskToCIDR_Mambo }
{ ns = 6,767, cidrnet = 0, method = MaskToCIDR_PerByte }
{ ns = 37,961, cidrnet = 0, method = MaskToCIDR_BTree }
{ ns = 2,118, cidrnet = 0, method = MaskToCIDR_Empty }
01101111.01101111.01101111.00000000 (111.111.111.0)
{ ns = 465,689, cidrnet = 18, method = MaskToCIDR_Fancy }
{ ns = 4,242, cidrnet = -1, method = MaskToCIDR_Fast }
{ ns = 67,996, cidrnet = -1, method = MaskToCIDR_Constant }
{ ns = 5,133, cidrnet = 24, method = MaskToCIDR_Ultra }
{ ns = 14,542, cidrnet = 18, method = MaskToCIDR_ConstantUltra }
{ ns = 6,285, cidrnet = -1, method = MaskToCIDR_Mambo }
{ ns = 7,879, cidrnet = -21, method = MaskToCIDR_PerByte }
{ ns = 40,017, cidrnet = -2, method = MaskToCIDR_BTree }
{ ns = 2,115, cidrnet = 0, method = MaskToCIDR_Empty }
00000001.00000001.00000001.00000000 (1.1.1.0)
{ ns = 368,824, cidrnet = 3, method = MaskToCIDR_Fancy }
{ ns = 4,227, cidrnet = -1, method = MaskToCIDR_Fast }
{ ns = 67,043, cidrnet = -1, method = MaskToCIDR_Constant }
{ ns = 4,920, cidrnet = 24, method = MaskToCIDR_Ultra }
{ ns = 13,979, cidrnet = 3, method = MaskToCIDR_ConstantUltra }
{ ns = 6,134, cidrnet = -1, method = MaskToCIDR_Mambo }
{ ns = 7,611, cidrnet = -24, method = MaskToCIDR_PerByte }
{ ns = 39,957, cidrnet = -2, method = MaskToCIDR_BTree }
{ ns = 2,115, cidrnet = 0, method = MaskToCIDR_Empty }
Und der Testcode:
public class CalculateCIDRProgram
{
private static uint[] dic = Enumerable.Range(0, 33).Select(i => i == 0 ? 0 : (uint)(~(1 << (32 - i)) + 1)).ToArray();
private static Stopwatch __watch;
public static void Main()
{
for (int i = 0; i < 33; i++)
{
byte[] intBytes = BitConverter.GetBytes(dic[i]);
if (BitConverter.IsLittleEndian)
Array.Reverse(intBytes);
Console.WriteLine($"{i}: {FormatBytes(intBytes)}");
}
__watch = Stopwatch.StartNew();
Test(IPAddress.Parse("255.255.255.255"));
Test(IPAddress.Parse("255.255.255.0"));
Test(IPAddress.Parse("255.255.254.0"));
Test(IPAddress.Parse("255.255.0.0"));
Test(IPAddress.Parse("255.0.0.0"));
Test(IPAddress.Parse("128.0.0.0"));
Test(IPAddress.Parse("0.0.0.0"));
Test(IPAddress.Parse("1.1.1.0"));
Test(IPAddress.Parse("111.111.111.0"));
}
private static void Test(IPAddress ip)
{
WriteHeader(ip);
var ipbytes = ip.GetAddressBytes();
var loops = 1000000;
//var loops = 1;
var cidrnet = null as int?;
var results = new List<object>();
__watch.Restart();
for (int i = 0; i < loops; i++)
cidrnet = MaskToCIDR_Fancy(ipbytes);
results.Add(new { ns = (1000000 * __watch.Elapsed.TotalMilliseconds/loops).ToString("0.000").PadLeft(10, ' '), cidrnet, method = nameof(MaskToCIDR_Fancy) });
__watch.Restart();
for (int i = 0; i < loops; i++)
cidrnet = MaskToCIDR_Fast(ipbytes);
results.Add(new { ns = (1000000 * __watch.Elapsed.TotalMilliseconds/loops).ToString("0.000").PadLeft(10, ' '), cidrnet, method = nameof(MaskToCIDR_Fast) });
fakeBool = true;
fakeInt = new Random().Next(33);
__watch.Restart();
for (int i = 0; i < loops; i++)
cidrnet = MaskToCIDR_Constant(ipbytes);
results.Add(new { ns = (1000000 * __watch.Elapsed.TotalMilliseconds/loops).ToString("0.000").PadLeft(10, ' '), cidrnet, method = nameof(MaskToCIDR_Constant) });
__watch.Restart();
for (int i = 0; i < loops; i++)
cidrnet = MaskToCIDR_Ultra(ipbytes);
results.Add(new { ns = (1000000 * __watch.Elapsed.TotalMilliseconds/loops).ToString("0.000").PadLeft(10, ' '), cidrnet, method = nameof(MaskToCIDR_Ultra) });
__watch.Restart();
for (int i = 0; i < loops; i++)
cidrnet = MaskToCIDR_ConstantUltra(ipbytes);
results.Add(new { ns = (1000000 * __watch.Elapsed.TotalMilliseconds/loops).ToString("0.000").PadLeft(10, ' '), cidrnet, method = nameof(MaskToCIDR_ConstantUltra) });
__watch.Restart();
for (int i = 0; i < loops; i++)
cidrnet = MaskToCIDR_Mambo(ipbytes);
results.Add(new { ns = (1000000 * __watch.Elapsed.TotalMilliseconds/loops).ToString("0.000").PadLeft(10, ' '), cidrnet, method = nameof(MaskToCIDR_Mambo) });
__watch.Restart();
for (int i = 0; i < loops; i++)
cidrnet = MaskToCIDR_PerByte(ipbytes);
results.Add(new { ns = (1000000 * __watch.Elapsed.TotalMilliseconds/loops).ToString("0.000").PadLeft(10, ' '), cidrnet, method = nameof(MaskToCIDR_PerByte) });
__watch.Restart();
for (int i = 0; i < loops; i++)
cidrnet = MaskToCIDR_BTree(ipbytes);
results.Add(new { ns = (1000000 * __watch.Elapsed.TotalMilliseconds/loops).ToString("0.000").PadLeft(10, ' '), cidrnet, method = nameof(MaskToCIDR_BTree) });
__watch.Restart();
for (int i = 0; i < loops; i++)
cidrnet = MaskToCIDR_Empty(ipbytes);
results.Add(new { ns = (1000000 * __watch.Elapsed.TotalMilliseconds/loops).ToString("0.000").PadLeft(10, ' '), cidrnet, method = nameof(MaskToCIDR_Empty) });
foreach (var result in results)
{
Console.WriteLine(result);
}
Console.WriteLine();
}
private static int fakeInt;
private static bool fakeBool;
private static int MaskToCIDR_Empty(byte[] bytes)
{
return 0;
}
private static int MaskToCIDR_BTree(byte[] bytes)
{
var addr = (uint)((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
return Array.BinarySearch(dic, addr);
}
private static int MaskToCIDR_PerByte(byte[] bytes)
{
int b0 = bytes[0];
int b1 = bytes[1];
int b2 = bytes[2];
int b3 = bytes[3];
switch (b3)
{
case 0x00: break;
case 0xFF: return 32;
case 0xFE: return 31;
case 0xFC: return 30;
case 0xF8: return 29;
case 0xF0: return 28;
case 0xE0: return 27;
case 0xC0: return 26;
case 0x80: return 25;
default:
return ~(
(b3 & 0x01) == 0 ? 32 :
(b3 & 0x02) == 0 ? 31 :
(b3 & 0x04) == 0 ? 30 :
(b3 & 0x08) == 0 ? 29 :
(b3 & 0x10) == 0 ? 28 :
(b3 & 0x20) == 0 ? 27 :
(b3 & 0x40) == 0 ? 26 :
25
);
}
switch (b2)
{
case 0x00: break;
case 0xFF: return 24;
case 0xFE: return 23;
case 0xFC: return 22;
case 0xF8: return 21;
case 0xF0: return 20;
case 0xE0: return 19;
case 0xC0: return 18;
case 0x80: return 17;
default:
return ~(
(b2 & 0x01) == 0 ? 24 :
(b2 & 0x02) == 0 ? 23 :
(b2 & 0x04) == 0 ? 22 :
(b2 & 0x08) == 0 ? 21 :
(b2 & 0x10) == 0 ? 20 :
(b2 & 0x20) == 0 ? 19 :
(b2 & 0x40) == 0 ? 18 :
17
);
}
switch (b1)
{
case 0x00: break;
case 0xFF: return 16;
case 0xFE: return 15;
case 0xFC: return 14;
case 0xF8: return 13;
case 0xF0: return 12;
case 0xE0: return 11;
case 0xC0: return 10;
case 0x80: return 9;
default:
return ~(
(b1 & 0x01) == 0 ? 16 :
(b1 & 0x02) == 0 ? 15 :
(b1 & 0x04) == 0 ? 14 :
(b1 & 0x08) == 0 ? 13 :
(b1 & 0x10) == 0 ? 12 :
(b1 & 0x20) == 0 ? 11 :
(b1 & 0x40) == 0 ? 10 :
9
);
}
switch (b0)
{
case 0x00: break;
case 0xFF: return 8;
case 0xFE: return 7;
case 0xFC: return 6;
case 0xF8: return 5;
case 0xF0: return 4;
case 0xE0: return 3;
case 0xC0: return 2;
case 0x80: return 1;
default:
return ~(
(b0 & 0x01) == 0 ? 8 :
(b0 & 0x02) == 0 ? 7 :
(b0 & 0x04) == 0 ? 6 :
(b0 & 0x08) == 0 ? 5 :
(b0 & 0x10) == 0 ? 4 :
(b0 & 0x20) == 0 ? 3 :
(b0 & 0x40) == 0 ? 2 :
1
);
}
return 0;
}
private static int MaskToCIDR_Mambo(byte[] bytes)
{
var addr = (uint)((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
switch (addr)
{
case 0xFFFFFFFF: return 32;
case 0xFFFFFFFE: return 31;
case 0xFFFFFFFC: return 30;
case 0xFFFFFFF8: return 29;
case 0xFFFFFFF0: return 28;
case 0xFFFFFFE0: return 27;
case 0xFFFFFFC0: return 26;
case 0xFFFFFF80: return 25;
case 0xFFFFFF00: return 24;
case 0xFFFFFE00: return 23;
case 0xFFFFFC00: return 22;
case 0xFFFFF800: return 21;
case 0xFFFFF000: return 20;
case 0xFFFFE000: return 19;
case 0xFFFFC000: return 18;
case 0xFFFF8000: return 17;
case 0xFFFF0000: return 16;
case 0xFFFE0000: return 15;
case 0xFFFC0000: return 14;
case 0xFFF80000: return 13;
case 0xFFF00000: return 12;
case 0xFFE00000: return 11;
case 0xFFC00000: return 10;
case 0xFF800000: return 9;
case 0xFF000000: return 8;
case 0xFE000000: return 7;
case 0xFC000000: return 6;
case 0xF8000000: return 5;
case 0xF0000000: return 4;
case 0xE0000000: return 3;
case 0xC0000000: return 2;
case 0x80000000: return 1;
case 0x00000000: return 0;
default:
return ~(
(addr & 0x80000000) == 0 ? 0 :
(addr & 0x40000000) == 0 ? 1 :
(addr & 0x20000000) == 0 ? 2 :
(addr & 0x10000000) == 0 ? 3 :
(addr & 0x08000000) == 0 ? 4 :
(addr & 0x04000000) == 0 ? 5 :
(addr & 0x02000000) == 0 ? 6 :
(addr & 0x01000000) == 0 ? 7 :
(addr & 0x00800000) == 0 ? 8 :
(addr & 0x00400000) == 0 ? 9 :
(addr & 0x00200000) == 0 ? 10 :
(addr & 0x00100000) == 0 ? 11 :
(addr & 0x00080000) == 0 ? 12 :
(addr & 0x00040000) == 0 ? 13 :
(addr & 0x00020000) == 0 ? 14 :
(addr & 0x00010000) == 0 ? 15 :
(addr & 0x00008000) == 0 ? 16 :
(addr & 0x00004000) == 0 ? 17 :
(addr & 0x00002000) == 0 ? 18 :
(addr & 0x00001000) == 0 ? 19 :
(addr & 0x00000800) == 0 ? 20 :
(addr & 0x00000400) == 0 ? 21 :
(addr & 0x00000200) == 0 ? 22 :
(addr & 0x00000100) == 0 ? 23 :
(addr & 0x00000080) == 0 ? 24 :
(addr & 0x00000040) == 0 ? 25 :
(addr & 0x00000020) == 0 ? 26 :
(addr & 0x00000010) == 0 ? 27 :
(addr & 0x00000008) == 0 ? 28 :
(addr & 0x00000004) == 0 ? 29 :
(addr & 0x00000002) == 0 ? 30 :
(addr & 0x00000001) == 0 ? 31 :
32);
}
}
private static int MaskToCIDR_ConstantUltra(byte[] bytes)
{
var b0 = bytes[0];
var b1 = bytes[1];
var b2 = bytes[2];
var b3 = bytes[3];
var result =
((b0 & 0x80) >> 7) +
((b0 & 0x40) >> 6) +
((b0 & 0x20) >> 5) +
((b0 & 0x10) >> 4) +
((b0 & 0x08) >> 3) +
((b0 & 0x04) >> 2) +
((b0 & 0x02) >> 1) +
(b0 & 0x01) +
((b1 & 0x80) >> 7) +
((b1 & 0x40) >> 6) +
((b1 & 0x20) >> 5) +
((b1 & 0x10) >> 4) +
((b1 & 0x08) >> 3) +
((b1 & 0x04) >> 2) +
((b1 & 0x02) >> 1) +
(b1 & 0x01) +
((b2 & 0x80) >> 7) +
((b2 & 0x40) >> 6) +
((b2 & 0x20) >> 5) +
((b2 & 0x10) >> 4) +
((b2 & 0x08) >> 3) +
((b2 & 0x04) >> 2) +
((b2 & 0x02) >> 1) +
(b2 & 0x01) +
((b3 & 0x80) >> 7) +
((b3 & 0x40) >> 6) +
((b3 & 0x20) >> 5) +
((b3 & 0x10) >> 4) +
((b3 & 0x08) >> 3) +
((b3 & 0x04) >> 2) +
((b3 & 0x02) >> 1) +
(b3 & 0x01)
;
return result;
}
private static int MaskToCIDR_Ultra(byte[] bytes)
{
var b0 = bytes[0];
var b1 = bytes[1];
var b2 = bytes[2];
var b3 = bytes[3];
return
b3 != 0 ? (
(b3 & 0x01) != 0 ? 32 :
(b3 & 0x02) != 0 ? 31 :
(b3 & 0x04) != 0 ? 30 :
(b3 & 0x08) != 0 ? 29 :
(b3 & 0x10) != 0 ? 28 :
(b3 & 0x20) != 0 ? 27 :
(b3 & 0x40) != 0 ? 26 :
25) :
b2 != 0 ? (
(b2 & 0x01) != 0 ? 24 :
(b2 & 0x02) != 0 ? 23 :
(b2 & 0x04) != 0 ? 22 :
(b2 & 0x08) != 0 ? 21 :
(b2 & 0x10) != 0 ? 20 :
(b2 & 0x20) != 0 ? 19 :
(b2 & 0x40) != 0 ? 18 :
17) :
b1 != 0 ? (
(b1 & 0x01) != 0 ? 16 :
(b1 & 0x02) != 0 ? 15 :
(b1 & 0x04) != 0 ? 14 :
(b1 & 0x08) != 0 ? 13 :
(b1 & 0x10) != 0 ? 12 :
(b1 & 0x20) != 0 ? 11 :
(b1 & 0x40) != 0 ? 10 :
9) :
b0 != 0 ? (
(b0 & 0x01) != 0 ? 8 :
(b0 & 0x02) != 0 ? 7 :
(b0 & 0x04) != 0 ? 6 :
(b0 & 0x08) != 0 ? 5 :
(b0 & 0x10) != 0 ? 4 :
(b0 & 0x20) != 0 ? 3 :
(b0 & 0x40) != 0 ? 2 :
1) :
0;
}
private static int MaskToCIDR_Constant(byte[] bytes)
{
int cidrnet = 0;
var done = false;
var invalid = false;
for (var i = 0; i < bytes.Length; i++)
{
for (int v = bytes[i], j = 0; j < 8; v = v << 1, j++)
{
if ((v & 0x80) == 0)
{
fakeBool = done;
done = true;
if (fakeBool)
fakeInt++;
else
fakeInt++;
}
else
{
invalid = done;
fakeBool = true;
if (done)
fakeInt++;
else
cidrnet++;
}
}
}
if (invalid)
cidrnet = ~cidrnet;
else
fakeInt = ~fakeInt;
return cidrnet;
}
private static int MaskToCIDR_Fast(byte[] bytes)
{
int cidrnet = 0;
var zeroed = false;
for (var i = 0; i < bytes.Length; i++)
{
for (int v = bytes[i]; (v & 0xFF) != 0; v = v << 1)
{
if (zeroed)
// invalid netmask
return ~cidrnet;
if ((v & 0x80) == 0)
zeroed = true;
else
cidrnet++;
}
}
return cidrnet;
}
private static int MaskToCIDR_Fancy(byte[] bytes)
{
return Convert
.ToString(BitConverter.ToInt32(bytes, 0), 2)
.ToCharArray()
.Count(x => x == '1');
}
private static void WriteHeader(IPAddress ip)
{
var binIp = FormatBytes(ip.GetAddressBytes());
Console.WriteLine($"{binIp} ({ip})");
}
private static string FormatBytes(byte[] bytes)
{
return string.Join(".", bytes.Select(b => Convert.ToString(b, 2).PadLeft(8, '0')));
}
}
Der Algorithmus gut so für die Optimierung definiert ist, können Sie den Entscheidungscode-Bit-Operationen und abgerollt Loops erzeugen und zwischenzuspeichern. Dies könnte auf IPv4 oder IPv6 angewendet werden, der einzige Unterschied ist die Anzahl der Bytes. – Rbjz