【问题标题】:Calculate number of available subnets in given network计算给定网络中可用子网的数量
【发布时间】:2014-09-05 11:49:29
【问题描述】:

我在计算网络中可用子网(或主机)的数量时遇到以下问题。例如,主子网是 /24 (255.255.255.0),其中包含两个 /25 (255.255.255.128) 或四个 /26 (255.255.255.192)。

因此,如果一个节点已被使用,则将只有一个 /25 或只有 3 次 /26。那么我应该如何计算可用子网的数量。换句话说,如何获得余数的数量和类型。 我想在 PHP 中执行这个算法。

【问题讨论】:

    标签: php networking ip binary-tree subnet


    【解决方案1】:

    我使用 python 来解决这个问题(所有代码都附上了,最后是整个脚本),但我确信 PHP 存在类似的解决方案库。由于这是旧的并且没有发布任何解决方案,我猜任何解决方案(在这种情况下是 Python 解决方案)都比没有解决方案要好。

    该脚本包含两个函数,一个使用BFS 计算“主”子网中的可用子网,另一个使用graphviz 创建一个pdf 绘图。

    我使用的算法是一个非常简单的 BFS。它基本上从顶部子网(“main”,/24)开始,并找出是否有任何使用的(“taken”)子网与其重叠/匹配。如果其中任何一个出现,算法会将其“子代”(/25) 排入队列,以便在同一进程中进行检查。如果算法命中没有“已采取”子节点的子网,则将其标记为“可用”。如果它命中与“已采用”完全匹配的子网,则将其标记为“已采用”。在任何其他情况下,迭代都会继续。

    可视化的绘制过程是相同的。

    这里是脚本描述(argparse-generated):

    usage: script.py [-h] -m M -t TAKEN [TAKEN ...] -o OUTPUT
    
    optional arguments:
      -h, --help            show this help message and exit
      -m M, --m M           main subnet to check
      -t TAKEN [TAKEN ...], --taken TAKEN [TAKEN ...]
                            taken subnets
      -o OUTPUT, --output OUTPUT
                            graphviz output file name (.pdf)
    

    使用您的参数运行脚本:

    subnet_script.py -m 255.255.255.0/24 -t 255.255.255.192/26 -o test
    

    给出这些结果:

    做一些更有趣的事情,比如:

    script.py -m 255.255.255.0/24 -t 255.255.255.192/26 255.255.255.128/30 -o test
    

    给出这些结果:

    我使用了ipaddressqueuegraphviz(用于python)模块,以及argparse 使脚本更易于使用。

    第一个函数:

    def get_available_subnets_set(main, taken):
        # we assume no subnets are available intially
        available = []
        q = queue.Queue()
        # add first node for expansion in the BFS process
        q.put(main)
    
        while q.qsize() > 0:
            subnet = q.get()
            for taken_subnet in taken:
                if taken_subnet.compare_networks(subnet) == 0:
                    # found matching subnet in taken, stop expanding
                    print("similar: %s and %s" % (subnet, taken_subnet))
                    break
                if taken_subnet.overlaps(subnet):
                    # still has overlaps somewhere in children, keep expanding
                    print("overlaps: %s and %s" % (subnet, taken_subnet))
                    for sub_subnet in subnet.subnets():
                        q.put(sub_subnet)
                    break
            else:
                # no overlaps with taken - this subnet is entirely available
                available.append(subnet)
    
        return set(available)
    

    第二个函数使用graphviz以类似的方式绘制结果:

    def make_subnet_graph(main, taken_subnets, available_subnets, filename):
    
        g = graphviz.Graph()
        q = queue.Queue()
        q.put(main)
        g.node(str(main))
    
        while q.qsize() > 0:
            subnet = q.get()
            for sub_subnet in subnet.subnets():
                if sub_subnet in available_subnets:
                    # draw as available (green)
                    g.node(str(sub_subnet), _attributes={"color": "green"})
                    g.edge(str(sub_subnet), str(subnet))
                    continue
                if sub_subnet in taken_subnets:
                    # draw as taken (red)
                    g.node(str(sub_subnet), _attributes={"color": "red"})
                    g.edge(str(sub_subnet), str(subnet))
                    continue
    
                # has mixed type subnets (taken / available) - go deeper
                g.node(str(sub_subnet))
                g.edge(str(sub_subnet), str(subnet))
                q.put(sub_subnet)
    
        # write file
        g.render(filename)
    

    整个事情连同 argparse:

    #!/usr/bin/env python3.4
    
    import ipaddress
    import argparse
    import queue
    import graphviz
    
    
    def get_available_subnets(main, taken):
        # we assume no subnets are available intially
        available = []
        q = queue.Queue()
        # add first node for expansion in the BFS process
        q.put(main)
    
        while q.qsize() > 0:
            subnet = q.get()
            for taken_subnet in taken:
                if taken_subnet.compare_networks(subnet) == 0:
                    # found matching subnet in taken, stop expanding
                    print("similar: %s and %s" % (subnet, taken_subnet))
                    break
                if taken_subnet.overlaps(subnet):
                    # still has overlaps somewhere in children, keep expanding
                    print("overlaps: %s and %s" % (subnet, taken_subnet))
                    for sub_subnet in subnet.subnets():
                        q.put(sub_subnet)
                    break
            else:
                # no overlaps with taken - this subnet is entirely available
                available.append(subnet)
    
        return available
    
    def make_subnet_graph(main, taken_subnets, available_subnets, filename):
    
        g = graphviz.Graph()
        q = queue.Queue()
        q.put(main)
        g.node(str(main))
    
        while q.qsize() > 0:
            subnet = q.get()
            for sub_subnet in subnet.subnets():
                if sub_subnet in available_subnets:
                    # draw as available (green)
                    g.node(str(sub_subnet), _attributes={"color": "green"})
                    g.edge(str(sub_subnet), str(subnet))
                    continue
                if sub_subnet in taken_subnets:
                    # draw as taken (red)
                    g.node(str(sub_subnet), _attributes={"color": "red"})
                    g.edge(str(sub_subnet), str(subnet))
                    continue
    
                # has mixed type subnets (taken / available) - go deeper
                g.node(str(sub_subnet))
                g.edge(str(sub_subnet), str(subnet))
                q.put(sub_subnet)
    
        # write file
        g.render(filename)
    
    
    if "__main__" == __name__:
        parser = argparse.ArgumentParser()
        parser.add_argument('-m', '--m', help='main subnet to check', required=True)
        parser.add_argument('-t', '--taken', nargs='+', help='taken subnets', required=True)
        parser.add_argument('-o', '--output', help='graphviz output file name (.pdf)', required=True)
        args = parser.parse_args()
    
        taken = [ipaddress.IPv4Network(subnet) for subnet in args.taken]
        main = ipaddress.IPv4Network(args.m)
        available = get_available_subnets_set(main, taken)
    
        make_subnet_graph(main, taken, available, args.output)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-13
      • 2012-11-22
      • 2013-11-01
      • 2013-03-03
      • 2017-10-08
      相关资源
      最近更新 更多