目标:
(1)编程实现一个子网划分的简单工具。
(2) 能够根据用户输入的网络地址和子网掩码,判断出用户输入的合法性及网络的类别(A、B、C地址)。
(3)能够计算出下列参数:子网数及有效子网、每个子网的主机数、每个子网IP范围及广播地址。
相关知识:
在用Python编写子网的划分模拟程序之前,就要理解到子网划分思路和主机数划分思路,那么首先要了解P位、M位、N位、子网位 M、N差、自动补零、二进制算法、点分十进制 IP 地址、IPv4地址分类的含义。
位:代表 bit 即长度,IP地址由 4 字节组成,如图 2-1 所示。
P位:网络位,即所给的IP对应子网掩 码“1”的个数。
N位:主机位,即所给的IP对应子网掩码“0”的 个数。
M位:子网位长度,即根据需要,从 N 位借 M 位长度的子网来划分。
子网位 M:是长度为M位的二进制数。
N差 = 准备划分IP地址的 N 位-当前算出划分需要的 N 位。
自动补零:补零的个数=需要位长度 - 当前位长度。
二进制算法:这里只用到了+1 和-1。
点分十进制IP地址:把算出的二进制IP地址每 8 个一取转换成10进制数加“.”和/P+M,P+M 即子网掩码1的长度,子网掩码是P+M个1和N个0组成。
IP地址构成图 |
将原来用于主机编码的二进制位,从高位(左端)拿出一部分出来用于子网的编号使用,即从主机位中借来进行网络划分,剩下的二进制位用于表达子网中的主机号,如图 2-2 所示,其次又要考虑到主机位为全0和全1不是有效的IP地址,最后准备开始编写python程序,实现子网划分的功能编写。
子网划分图 |
一个拥有许多物理网络的单位,可将所属的物理网络划分为若干个子网,划分子网纯属一个单位内部的事情,本单位以外的网络看不见这个网络是由多少个子网组成,因这个单位对外仍然表现为一个网络。划分子网的方法是从网络的主机号借用若干位作为子网号stbnet-id,当然主机号也就相应减少了同样的位数。于是两级IP地址在本单位内部就变为三级IP地址:网络号、子网号和主机号。也可以用以下记法来表示:
IP地址: :二{V网络号〉,v子网号〉,V主机号> }
子网号和主机号是由原先IP地址的主机地址部分分割成两部分得到的,因此,划分子网的能力依赖于被子网化的IP地址类型。IP地址中主机地址的位数越多,能分得更多的子网和主机。实际上是把主机地址的一部分拿走用于识别子网。将原来用于主机编码的二进制位,从高位(左端)拿出一部分出来用于子网的编号使用,即从主机位中借来进行网络划分,剩下的二进制位用于表达子网中的主机号,如图2.3.1所示,其次又要考虑到主机位为全0和全1不是有效的IP地址,最后准备开始编写python程序,实现子网划分的功能编写。
子网划分规则
子网掩码是一个网络或一个子网的重要属性。为了使路由器能够很方便地从数据报中的目的IP地址中提取出所要找的子网的网络地址,路由器就要使用三级IP地址的子网掩码。把三级IP地址的子网掩码和收到的数据报的目的IP地址逐为相与即可得出所要找的子网的网络地址。RFC 950定义了子网掩码的使用,子网掩码是以个32位的2进制数,其对应网络地址的所有位置都为1,对应于主机地址的所有位置都为0。
由此可知,A类网络的默认子网掩码是255.0.0.0 ,B类网络的默认子网掩码255.255.0.0 ,C类网络的默认子网掩码是255.255.255.0 。将子网掩码和IP地址按位进行逻辑与运算,得到IP地址的网络地址,剩下的部分就是主机地址,从而区分出任意IP地址中的网络地址和主机地址。子网掩码常用点分十进制表示,我们还可以用CIDR的网络前缀法表示掩码,即“/V网络地址位数”;如138.96.0.0/16表示B类网络138.96.0.0的子网掩码为255.255.0.0。
IP判断:子网掩码告知路由器,1P地址的前多少位是网络地址,后多少位(剩余位)是主机地址,使路由器正确判断任意IP地址是否是本网段的,从而正确地进行路由。在RFC950成为因特网正式标准后,路由器在和相邻路由器交换路由信息时,必须把自己所在网络的子网掩码告诉相邻路由器。在路由器的路由表中的每一个项目,除了要给出目的网络地址外,还必须同时给出该网络的子网掩码。在使用固定长度子网时,所划分的所有子网的子网掩码都是一致的。如图2.3.1所示:
子网划分规则 |
提示用户输入网络地址、子网掩码并判断其合法性;若输入的网络地址或子网掩码有其中任意一个输入不合法就报错,需重新输入合法的IP地址和子网掩码;在二者都合法的情况下,判断其类别(A类、B类、C类);最后分别计算其子网数及有效子网、每个子网的主机数、每个子网IP范围及广播地址。
2.3.4 程序设计流程图
程序设计流程图 |
输入网络地址的合法性
网络地址即子网地址。网络地址和IP地址的关系如下:
IP地址 = 子网地址+主机地址
根据TCP/IP协议,连接在Internet上的每个设备都必须有一个IP地址,它一个32位的二进制数,可以用十进制数字形式书写,每8个二进制位为一组,用一个十进制数来表示,即0-255,每组之间用“.”隔开,如:6.16.122.204。
本设计中关于网络地址的合法性判断也可简单的归结为与IP地址的合法性判断类似。关于IP地址的合法性验证很简单,方法也很多,比如字符串分解、正则表达式等。本次设计中判断网络地址是否合法的方法为判断输人是否为4段,每段是否为0.255的数字。
输入子网掩码的合法性
简单来讲,子网掩码就类似这样一串数字,前面一段是连续的1,类似于11111111,后面一段是连续的0,类似0000,这样合法的样子11111000000000总共是32位。一个合法的子网掩码要满足如下条件:
1、是合法的IP地址;
2、二进制码要相邻,即形如.1..1000...0的形式;
3、与IP地址对应,A、B、C、D各类IP地址都有对应的掩码范围。
判断子网掩码的方法:先验证是否为合法IP,然后将掩码转化成32无符号整型,取反。为0..00111..」,然后再加1为0...0..0,此时为25,如果满足就为合法掩码。无论是哪一类掩码,第一个字段都是255。或者查找字符串中的子串0T,若查不到就合法,否则不合法。
IP地址的类型判断
Internet组织机构定义了五种IP地址,用于主机的有A、B、C三类地址。A、B、C三类地址的特征:当将IP地址写成二进制形式时,A类地址的第一位总是0 ,B类地址的前两位总是10 ,C类地址的前三位总是110 。
子网数、有效子网数、主机数和IP范围,广播地址的计算
(1)子网数:子网数可以通过子网掩码中二进制1的位数(即网络段所在的二进制位数)减去此子网掩码所在标准类的网络段所占的二进制位数(例: A类8位,B类16位,C类24位)计算得到。
(2)有效子网数:有效子网数二子网数*2
(3)主机数主机数即用子网掩码中主机位数的多少来计算,主机数=2八二进制主机位数*2减2是因为主机不包含网络地址和广播地址。
(4)广播地址:将网络地址中的网络地址部分不变,主机地址变为全1 ,结果就是广播地址。
(5)IP范围:ip范围即含在本网段内的所有主机,网络地址+1为第一个主机地址,广播地址/为最后一个主机地址,所以ip地址范围是:网络地址+1至广播地址。
图2.4 三类地址中网络号字段和主机号字段 |
结果呈现
调试报告与使用说明
通过运行程序,按照“输入样式提示”(如图2.5.1.1)输入划分的ip:
程序正确输入格式示范截图 |
输入合法的IP:183.164.128.0/17/8,其中183.164.128.0表示是ipv4地址,17表示掩码,8表示要划分8个子网。计算结果如图2.5.1.2:
当输入合法的IP时,183.164.128.0/17/8子网划分划分程序运行结果截图 |
分析:其中考虑到之前所提示过,主机位为全0和全1不是有效的IP地址,故在最大主机位减去2,得到可用的最大IP为4094个。可以看出,计算的所有结果与上节分析表中的结果完全一致。
当输入的IP不合法或掩码不规范,直接退出程序,如图2.5.1.3和图2.5.1.4:
错误的ip直接退出程序的截图 |
错误的子网掩码导致程序终止截图 |
结果展示
程序运行结果展示 |
在划分子网时,不仅要考虑目前需要,还应了解将来需要多少子网和主机。对子网掩码使用必须要更多的子网位,可以得到更多的子网,节约了IP地址资源,若将来需要更多子网时,不用再重新分配IP地址,但每个子网的主机数量有限;反之,子网掩码使用较少的子网位,每个子网的主机数量允许有更大的增长,但可用子网数量有限。一般来说,一个网络中的节点数太多,网络会因为广播通信而饱和,所以,网络中的主机数量的增长是有限的,也就是说,在条件允许的情况下,会将更多的主机位用于子网位。
综上所述,子网掩码的设置关系到子网的划分。子网掩码设置的不同,所得到的子网不同,每个子网能容纳的主机数目不同。若设置错误,可能导致数据传输错误。
附源码如下:
import sys
'''初始化'''
print("请输入iPv4地址:(并输入子网掩码及要划分的子网数量)")
print("输入样式提示:1.2.3.0/24/8 \n其中:1.2.3.0为ip,24为子网掩码,8是实现划分8个网段.")
str = input("请输入你需要划分的ip:\n") # 初始化网络号、子网掩码、需求子网数量
# 切割网络号、子网掩码、子网数,判断输入ip是否合法
temp = str.split('/')
if len(temp) != 3:
print ("输入不合法,程序终止!")
sys.exit()
# 转换子网掩码、子网数量
subnetMask = int(temp[1]) # 子网掩码
subnetNumber = int(temp[2]) # 子网数量
if (subnetMask < 2) or (subnetNumber < 2):
print("子网掩码、子网数量至少为2,程序终止!")
sys.exit()
# 切割、转换网络号到十进制
temp2 = temp[0].split('.')
if len(temp2) != 4:
print("网络号不合法,程序终止!")
sys.exit()
ip10 = [0]*4 # 初始化每一段IP地址,十进制
for i in range(4): # 转为整形
ip10[i] = int(temp2[i])
if (ip10[i] < 0) or (ip10[i] > 255):
print ("网络号不合法,程序终止!")
sys.exit()
# 转换网络号到二进制
ip2 = [0]*32 # 初始化每一位IP地址,二进制
flag = 0 # flag标记是否停止计算网络前缀
preNet = 32 # preNet网络前缀个数(32-从后往前数,第一个不为0的数字)
k = 31
for i in range(3, -1, -1): # 转为二进制,并保存到数组
for j in range(8):
ip2[k] = ip10[i] >> j & 1 # >>运算,右移n位,高位补0
k -= 1
if (flag == 0) and (ip2[k+1] == 0): # 计算网络前缀
preNet -= 1
else:
flag = 1
if subnetMask < preNet:
print("该网络号的子网掩码不合法,程序终止!")
sys.exit()
if (1 << (32 - subnetMask)) < subnetNumber:
# 子网数不可超过主机数量,<<运算,左移n位,相当于2的n次方
print( "需求子网数超出最大主机数量,程序终止!")
sys.exit()
# 计算应当划分的子网数量和每个子网的最大主机数量
realSubnetNumber = subnetNumber - 1
# 假设输入的子网数量为2的幂次方,此处-1是避免是2的幂的情况,
#1是例外,但是上面已经排除
power = 1 # 应该为2的几次幂
while (realSubnetNumber >> 1) != 0: # 相当于a=a/2,a/2!=0
realSubnetNumber = realSubnetNumber >> 1
power += 1
realSubnetNumber = 1 << power
maxHost = 1 << (32 - preNet - power) # 每个子网的最大主机数量
#分配ip
preIp = [[0 for col in range(4)] for row in range(realSubnetNumber)]
# 第一个ip
sufIp = [[0 for col in range(4)] for row in range(realSubnetNumber)]
# 最后一个ip
for i in range(realSubnetNumber):
'''设置子网号'''
for j in range(power): # 子网号,递增
ip2[subnetMask + power - j - 1] = i >> j & 1
'''设置第一个ip'''
for j in range(subnetMask + power, 32): # 填充0
ip2[j] = 0
for j in range(4): # 计算每一段IP地址,十进制
t = 0 # 计算数组对应的值
for k in range(8):
t += ip2[(j << 3) + k] << (7 - k)
preIp[i][j] = t # 第一个ip
'''设置最后一个ip'''
for j in range(subnetMask + power, 32): # 填充1
ip2[j] = 1
for j in range(4):
t = 0
for k in range(8):
t += ip2[(j << 3) + k] << (7 - k)
sufIp[i][j] = t # 最后一个ip
#输出
print (u"根IP地址为:", temp[0], u" 子网掩码位数为:", subnetMask)
print ("需求子网数量为:", subnetNumber, " 实际划分的子网数量为:", realSubnetNumber)
print ("每个子网最大的主机数为:", maxHost-2) #-2的原因是全0和全1的不能用
for i in range(realSubnetNumber):
print ("第 ", i+1, " 个子网可用地址范围:",\
preIp[i][0], ".", preIp[i][1], ".", preIp[i][2], ".", (preIp[i][3] + 1), " ———— ",\
sufIp[i][0], ".", sufIp[i][1], ".", sufIp[i][2], ".", (sufIp[i][3] - 1),\
" 网络地址:", preIp[i][0], ".", preIp[i][1], ".", preIp[i][2], ".", preIp[i][3],\
" 广播地址:", sufIp[i][0], ".", sufIp[i][1], ".", sufIp[i][2], ".", sufIp[i][3])
写在最后文章来源:https://www.toymoban.com/news/detail-795205.html
以上内容为本人练习,仅供参考,若读者发现内容有误请私信指正,后续将上传C语言版本,敬请期待~文章来源地址https://www.toymoban.com/news/detail-795205.html
到了这里,关于子网划分工具的设计与实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!