python实现路由自动聚合(原创)

该程序的主要作用是对输入的一系列 IPv4 地址进行校验、去重、排序、聚合(地址压缩),并最终将处理后的结果以十进制 IP 地址格式输出。下面是程序各部分功能的详细分析:

1. 函数定义

1.1 D2B(IP) 十进制IP转为二进制IP
def D2B(IP):
    tmp = IP.split('.')
    Blist = []
    Blist.append("{:08b}".format(int(tmp[0])))
    Blist.append("{:08b}".format(int(tmp[1])))
    Blist.append("{:08b}".format(int(tmp[2])))
    Blist.append("{:08b}".format(int(tmp[3].split('/')[0])))
    Blist.append(int(tmp[3].split('/')[1]))
    BIPtmp = ''
    for i in Blist:
        BIPtmp += str(i)
    BIP = BIPtmp[:32:] + '/' + BIPtmp[32::]
    return BIP
  • 功能:将十进制的 IPv4 地址(带子网掩码,如 192.168.1.0/24)转换为二进制格式。
  • 步骤:
    1. 将输入的 IP 地址按 . 分割成四部分。
    2. 把每部分转换为 8 位二进制字符串。
    3. 提取子网掩码部分。
    4. 将二进制字符串和子网掩码拼接成完整的二进制 IP 地址。
1.2 B2D(IP) 二进制IP转为十进制IP
def B2D(IP):
    tmp = IP.split('/')
    Dlist = []
    Dlist.append(int(tmp[0][:8:], 2))
    Dlist.append(int(tmp[0][8:16:], 2))
    Dlist.append(int(tmp[0][16:24:], 2))
    Dlist.append(int(tmp[0][24:32:], 2))
    DIPtmp = ''
    for i in Dlist:
        DIPtmp += str(i)
        DIPtmp += '.'
    DIP = DIPtmp[:-1:] + '/' + str(tmp[1])
    return DIP
  • 功能:将二进制的 IPv4 地址(带子网掩码)转换为十进制格式。
  • 步骤:
    1. 将输入的二进制 IP 地址按 / 分割成 IP 部分和子网掩码部分。
    2. 将 IP 部分每 8 位转换为十进制整数。
    3. 将十进制整数用 . 连接起来,并拼接子网掩码,形成完整的十进制 IP 地址。
1.3 check(IN) 校验
def check(IN):
    IN1 = IN.split('/')
    IN2 = IN1[0].split('.')
    IN2.append(IN1[1])
    IN2 = list(map(int, IN2))
    if len(IN2) != 5:
        return False
    for i in IN2[0:4:]:
        if i not in range(0, 256):
            return False
    if IN2[4] not in range(0, 33):
        return False
    return True
  • 功能:检查输入的 IPv4 地址(带子网掩码)格式是否正确。
  • 步骤:
    1. 检查输入的 IP 地址是否能正确分割成 5 个部分(4 个 IP 段和 1 个子网掩码)。
    2. 检查每个 IP 段是否在 0 到 255 之间。
    3. 检查子网掩码是否在 0 到 32 之间。
1.4 打印函数
def print1(element):
    a, b0 = element.split('/')
    b = int(b0)
    print(a[:b], a[b:] + '/' + b0)

def print2(list):
    for i in list:
        print1(i)

def print3(list):
    for i in list:
        print(i)
  • print1(element):将 IP 地址按子网掩码分割成网络前缀和剩余部分并打印。
  • print2(list):对列表中的每个 IP 地址调用 print1 函数进行打印。
  • print3(list):打印列表中的每个元素。
1.5 地址压缩函数
功能概述

aggregation 函数的主要功能是对输入的二进制 IP 地址前缀列表进行聚合(地址压缩)操作。在网络地址规划中,地址聚合可以将多个相邻的 IP 地址块合并成一个更大的地址块,从而减少路由表的条目数量,提高路由效率。该函数通过递归的方式,不断检查相邻的 IP 地址前缀是否可以合并,直到无法再进行合并为止。

代码注解
def aggregation(INlist=[], flag=1):
    # 如果 flag 为 0,表示上一轮没有发生合并操作,直接返回输入列表
    if flag == 0:
        return INlist
    # 获取列表的长度
    i = len(INlist) - 1
    # 初始化 flag 为 0,表示当前轮次还没有发生合并操作
    flag = 0
    # 从列表末尾开始向前遍历
    while i > 0:
        # 获取当前元素和前一个元素
        IP = INlist[i - 1]
        IP2 = INlist[i]
        # 提取当前元素和前一个元素的前缀(去掉最后一位)
        prefix = IP[:-1]
        prefix2 = IP2[:-1]
        # 如果两个前缀相同,说明可以合并
        if prefix == prefix2:
            # 删除当前元素
            del INlist[i]
            # 将前一个元素更新为合并后的前缀
            INlist[i - 1] = prefix
            # 跳过下一个元素,因为已经合并了
            i -= 2
            # 设置 flag 为 1,表示发生了合并操作
            flag = 1
        else:
            # 如果不能合并,继续向前遍历
            i -= 1
    # 递归调用 aggregation 函数,继续进行合并操作
    return aggregation(INlist, flag)
测试用例及结果
测试用例 1:简单合并
# 输入的二进制 IP 地址前缀列表
input_list = [
'10000000000000000000000000000000',
'10000000000000000000000000000001']
# 调用 aggregation 函数进行合并
result = aggregation(input_list)
# 输出结果
print("合并后的结果:", result)

预期结果

合并后的结果: ['1000000000000000000000000000000']

解释:输入的两个前缀只有最后一位不同,因此可以合并成一个更短的前缀。

测试用例 2:无法合并
input_list = [
'10000000000000000000000000000000', 
'11000000000000000000000000000000']
result = aggregation(input_list)
print("合并后的结果:", result)

预期结果

合并后的结果: [
'10000000000000000000000000000000', 
'11000000000000000000000000000000'
]

解释:输入的两个前缀差异较大,无法进行合并,因此结果与输入相同。

测试用例 3:多次合并
input_list = [
'10000000000000000000000000000000',
'10000000000000000000000000000001', 
'10000000000000000000000000000010', 
'10000000000000000000000000000011'
 ]
result = aggregation(input_list)
print("合并后的结果:", result)

预期结果

合并后的结果: ['100000000000000000000000000000']

解释:输入的四个前缀可以逐步合并,最终得到一个更短的前缀。

2. 主函数 main()

def main():
    while True:
        INPUT = input() #输入结束
        if INPUT == '':
            break
        if check(INPUT): #校验&去重
            tail = int(INPUT.split('/')[1])
            pBIP = D2B(INPUT)[0:tail]
            pINjihe.add(pBIP)
        else: #校验未通过
            continue
        pINlist = list(pINjihe)
        pINlist.sort() #排序,方便后续进行地址聚合
    pOUTlist = aggregation(pINlist) #地址聚合
    for i in pOUTlist:
        tail = len(i)
        OUTlist.append(i + (32 - tail) * '0' + '/' + str(tail)) #更改为标准二进制格式
    print3(list(map(B2D, OUTlist))) #更改为十进制格式并输出
  • 主程序逻辑:负责读取输入、校验、去重、排序、聚合和输出结果。
  • 步骤:
    1. 循环读取用户输入,直到输入为空。
    2. 对每个输入进行格式校验,如果校验通过,将其转换为二进制并提取网络前缀,添加到集合 pINjihe 中进行去重。
    3. 将集合转换为列表并排序。
    4. 对排序后的列表进行地址聚合。
    5. 将聚合后的结果补充为标准的 32 位二进制 IP 地址,并添加到 OUTlist 中。
    6. OUTlist 中的二进制 IP 地址转换为十进制格式并输出。

该程序可以帮助用户对输入的 IPv4 地址进行处理,去除重复地址,合并相邻的网络前缀,最终输出经过优化的 IPv4 地址列表。

3. 测试用例

输入:

192.168.238.0/24
192.168.239.0/24
192.168.240.0/24
192.168.241.0/24
192.168.242.0/24
192.168.243.0/24
192.168.244.0/24
192.168.245.0/24
192.168.246.0/24
192.168.247.0/24
192.168.248.0/24
192.168.249.0/24
192.168.250.0/24
192.168.251.0/24
192.168.252.0/24
192.168.253.0/24
192.168.254.0/24
192.168.255.0/24

输出:

192.168.238.0/23
192.168.238.0/23
192.168.240.0/20

4. 程序源码

pINjihe=set()
OUTlist=[]
#将十进制IP转化为二进制
def D2B(IP):
    tmp=IP.split('.')
    Blist=[]
    Blist.append("{:08b}".format(int(tmp[0])))
    Blist.append("{:08b}".format(int(tmp[1])))
    Blist.append("{:08b}".format(int(tmp[2])))
    Blist.append("{:08b}".format(int(tmp[3].split('/')[0])))
    Blist.append(int(tmp[3].split('/')[1]))
    BIPtmp=''
    for i in Blist:
        BIPtmp+=str(i)
    BIP=BIPtmp[:32:]+'/'+BIPtmp[32::]
    return BIP
#将二进制IP转化为十进制
def B2D(IP):
    tmp=IP.split('/')
    Dlist=[]
    Dlist.append(int(tmp[0][:8:],2))
    Dlist.append(int(tmp[0][8:16:],2))
    Dlist.append(int(tmp[0][16:24:],2))
    Dlist.append(int(tmp[0][24:32:],2))
    DIPtmp=''
    for i in Dlist:
        DIPtmp+=str(i)
        DIPtmp+='.'
    DIP=DIPtmp[:-1:]+'/'+str(tmp[1])
    return DIP
#IP地址格式检测
def check(IN):
    IN1=IN.split('/')
    IN2=IN1[0].split('.')
    IN2.append(IN1[1])
    IN2=list(map(int,IN2))
    if len(IN2) != 5: #检测格式
        return False
    for i in IN2[0:4:]: #检测IP地址范围
        if i not in range(0,256):
            return False
    if IN2[4] not in range(0,33): #检测网络位范围
        return False
    return True
#各种打印方法
def print1(element):
    a,b0=element.split('/')
    b=int(b0)
    print(a[:b],a[b:]+'/'+b0)
def print2(list):
    for i in list:
        print1(i)
def print3(list):
    for i in list:
        print(i)
#地址压缩函数
def aggregation(INlist=[],flag=1):
    if flag==0:
        return INlist
    i=len(INlist)-1
    flag=0
    while i>0:
        IP=INlist[i-1]
        IP2=INlist[i]
        prefix=IP[:-1]
        prefix2=IP2[:-1]
        if prefix==prefix2:
            del INlist[i]
            INlist[i-1]=prefix
            i-=2
            flag=1
        else:
            i-=1
    return aggregation(INlist,flag)

def main():
    while True:
        INPUT=input()
        if INPUT == '': #输入结束
            break
        if check(INPUT): #校验&去重
            tail=int(INPUT.split('/')[1])
            pBIP=D2B(INPUT)[0:tail]
            pINjihe.add(pBIP)
        else: #校验未通过
            continue
        pINlist=list(pINjihe)
        pINlist.sort() #排序
    pOUTlist=aggregation(pINlist) #压缩
    for i in pOUTlist:
        tail=len(i)
        OUTlist.append( i+ (32-tail)*'0' +'/'+ str(tail) ) #更改为标准二进制格式
        print3(list(map(B2D,OUTlist))) #更改为十进制格式并输出
main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值