派生子网定义的反转

时间:2009-07-03 09:23:12

标签: algorithm ip-address subnet

IP子网由两部分组成,网络和前缀长度或掩码 例如192.168.0.0/16(或192.168.0.0/255.255.0.0)。

据说192.168.1.1之类的IP地址与此子网匹配,因为

(192.168.1.1 & 255.255.0.0) == 192.168.0.0

我对所谓的子网逆转感兴趣 这是这样描述的,

  

对于给定的 SubnetA (例如,NetworkA / MaskA),
   SubnetA 的倒数是 k 子网的列表,例如,

     

如果IP地址 A ,则匹配 SubnetA
   A k 子网中的任何一个都不匹配,而且   每个IP地址 B SubnetA
不匹配   将完全匹配 1 这些 k 子网。

代码没有必要,我对正确和最佳的方法感兴趣。


我有优化的答案,请参考下面的参考,因此它不会分散人们尝试这个问题的注意力。保留了对Rafał答案的接受,因为他也是第一次接受了。

4 个答案:

答案 0 :(得分:2)

b中每个未屏蔽的位A的一个子网,与A中的所有先前位匹配,在b上不同,屏蔽了以下所有位。这样,不在i中的每个地址A将只匹配上述网络中的一个,即负责i的第一位与A不匹配的网络。< / p>

答案 1 :(得分:0)

嗯。我会说它基本上是A以外的任何子网,具有相同的掩码...

答案 2 :(得分:0)

如果您想象从0.0.0.0/32开始的所有子网的树,每个位都分支,您希望所有分支都不通向您的子网。向上一步(位),将该位置空并将此节点的兄弟(在适当的位置有不同的位)添加到您的集合中。 (和Rafał说的一样,只是表达不同。)你可以这样做(使用C#代码):

using System;
using System.Text;

namespace so_subnet_complement
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Enter subnet in the 192.168.0.0/16 format.");
            string[] line = Console.ReadLine().Split('/');
            string[] segments = line[0].Split('.');
            uint ip = 0;
            uint multiplier = 1;
            for (int i = 3; i >= 0; i--)
            {
                ip += byte.Parse(segments[i]) * multiplier;
                multiplier *= 0x100;
            }
            int mask = int.Parse(line[1]);

            Console.WriteLine("Complement subnets:");
            writeComplementSubnets(ip, mask);
        }

        static void writeComplementSubnets(uint ip, int mask)
        {
            for (;mask < 32; mask++)
            {
                uint newIp =(uint)(ip & (0xFFFFFFFF << mask) ^ (1 << mask));
                Console.WriteLine("{0}/{1}", ipToString(newIp), mask);
            }
        }

        static string ipToString(uint ip)
        {
            StringBuilder result = new StringBuilder(15);
            uint mask = 0xFF000000;
            int shift = 24;
            for (int i = 0; i < 4; i++)
            {
                result.Append((ip & mask) >> shift);
                mask >>= 8;
                shift -= 8;
                if (i < 3)
                    result.Append('.');
            }
            return result.ToString();
        }
    }
}

最重要的是writeComplementSubnets方法。 IP地址以自然(对我而言)表示形式表示,因此192.168.0.0变为0xC0A80000

编辑:我意识到这里绝对没有必要进行递归。似乎函数式编程有时会导致错误的思考。

答案 3 :(得分:0)

我在此代码段中提供了优化答案以供参考。

unsigned int network; // 32-bit network. Say (192.168.0.0 or 0xC0A80000)
unsigned int mask; // 32-bit mask (0xFFFF0000 for the example case)

i = 0; // to iterate over the network bits
do {
    bitmask = (unsigned int)(0x80000000 >> i)
    invmask = (unsigned int)(0xFFFFFFFF << (31-i));

    invnet = (invmask & network) ^ bitmask;
    printSubnet(invnet, invmask); // this stores/prints the subnet

} while (mask && i<32); // only while we have valid mask

接受Rafał的回答,因为他也是第一次做到了。


以下是192.168.0.0/16的反转,以检查正确性。

[1] 0.0.0.0 / 128.0.0.0         ;    00000000
[2] 128.0.0.0 / 192.0.0.0       ;    80000000
[3] 224.0.0.0 / 224.0.0.0       ;    e0000000
[4] 208.0.0.0 / 240.0.0.0       ;    d0000000
[5] 200.0.0.0 / 248.0.0.0       ;    c8000000
[6] 196.0.0.0 / 252.0.0.0       ;    c4000000
[7] 194.0.0.0 / 254.0.0.0       ;    c2000000
[8] 193.0.0.0 / 255.0.0.0       ;    c1000000
[9] 192.0.0.0 / 255.128.0.0     ;    c0000000
[10] 192.192.0.0 / 255.192.0.0  ;    c0c00000
[11] 192.128.0.0 / 255.224.0.0  ;    c0800000
[12] 192.176.0.0 / 255.240.0.0  ;    c0b00000
[13] 192.160.0.0 / 255.248.0.0  ;    c0a00000
[14] 192.172.0.0 / 255.252.0.0  ;    c0ac0000
[15] 192.170.0.0 / 255.254.0.0  ;    c0aa0000
[16] 192.169.0.0 / 255.255.0.0  ;    c0a90000