Получить CIDR из сетевой маски

Я придумал это для расчета CIDR, но я уверен, что это не так. самый быстрый способ:

public int MaskToCIDR(IPAddress ip)
{
  return Convert
         .ToString(BitConverter.ToInt32(ip.GetAddressBytes(), 0), 2)
         .ToCharArray()
         .Count(x => x == '1');
}

Тестовое задание:

Console.WriteLine(MaskToCIDR(new IPAddress(new byte[]{255,255,255,255}))); // 32
Console.WriteLine(MaskToCIDR(new IPAddress(new byte[]{255,255,255,0}))); // 24
Console.WriteLine(MaskToCIDR(new IPAddress(new byte[]{255,255,0,0}))); // 16
Console.WriteLine(MaskToCIDR(new IPAddress(new byte[]{255,0,0,0}))); // 8
Console.WriteLine(MaskToCIDR(new IPAddress(new byte[]{0,0,0,0}))); // 0

Есть ли более быстрый способ и как насчет IPv6?


person raspi    schedule 30.04.2016    source источник
comment
Алгоритм хорошо определен, поэтому для оптимизации вы можете генерировать и кэшировать код принятия решений, используя битовые операции и развернутые циклы. Это может быть применено к IPv4 или IPv6, единственная разница заключается в количестве байтов.   -  person Rbjz    schedule 23.09.2016


Ответы (3)


Вы можете получить в 10-100 раз быстрее в зависимости от того, как вы хотите обрабатывать недопустимую сетевую маску, см. - c код для действительного сетевая маска и https://superuser.com/questions/601252/is-225-225-225-128-a-valid-subnet-mask. Вот мой результат теста (где ваше оригинальное предложение - фантазии, я также экспериментировал с выполнением с постоянным временем из любопытства).

Короче говоря: работайте в двоичном коде, используйте константы, разворачивайте циклы. Версия Ultra может быть лучшей. Для недействительной сетевой маски возвращается ближайшая, содержащая действительную сетевую маску.

А как насчет IPv6? Возможно, мы преждевременно оптимизировали... Я надеюсь, что никто не посмеет использовать нотацию сетевой маски старого стиля для IPv6. Это должно быть забыто.

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 }

И тестовый код:

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')));
    }
}
person Rbjz    schedule 23.09.2016

Ваш исходный код неверен - результат GetHashCode() IP-адреса не будет (или, скорее, не должен) говорить вам что-либо об этом отдельном IP-адресе.

Учитывая, что маска подсети в CIDR-нотации — это просто количество битов, которые установлены в 1, начиная со старшего конца, вы можете вычислить это довольно быстро, используя операторы сдвига битов и двоичный оператор И.

person yaakov    schedule 30.04.2016
comment
Код работает нормально. Сначала IP-адрес, который всегда вызывается с сетевой маской, преобразуется в целое число, которое затем преобразуется в двоичную строку, которая преобразуется в массив символов. Затем вычислите все символы, содержащие «1», из этого массива символов, и это даст правильный CIDR. Итак, ваш комментарий. Ваш исходный код неверен. - person raspi; 30.04.2016
comment
@raspi ‘ip.GetHashCode()’ неверен. Он работает только случайно и может сломаться в любой новой версии .NET Framework. - person yaakov; 30.04.2016
comment
Не могли бы вы предоставить ссылку на это? msdn.microsoft.com /en-us/library/ ничего не говорит о взломе в будущем. - person raspi; 30.04.2016
comment
См. msdn.microsoft.com/ ru/библиотека/ - person yaakov; 30.04.2016
comment
Хорошо, теперь он использует GetAddressBytes() - person raspi; 01.05.2016

Мое решение для IPv4

Очень простой:

int cidr = Convert.ToString(mask.Address, 2).Count( o => o == '1'); 

«.Adress» устарел, но все еще поддерживается.

Пояснение на основе 255.255.255.240:

IPAddress mask = new IPAddress(new byte[] { 255, 255, 244, 240 });

// adressBinAsString = 11110000111101001111111111111111
string maskBinAsString = Convert.ToString(mask.Address, 2); 

// cidr = 28
int cidr = Convert.ToString(mask.Address, 2).Count( o=> o == '1'); // 
person marsh-wiggle    schedule 03.05.2020