用Python开发一个交互式网络和IP地址计算器
off999 2024-10-30 03:07 32 浏览 0 评论
今天从Python的角度来聊下计算机网络这行基础中的基础的话题:网络和IP地址计算(注:本文里的IP指的是IPv4,不涉及IPv6)。相信几乎每位网工读者在平时的工作和学习中都用过类似下图的在线网络和IP地址计算器吧:
这类前人(或者说码农们)造出的轮子的确很好用,但是很少有网工明白它们背后的工作原理(也就是代码是怎么写出来的)。作为有志成为NetDevOps Engineer的我们有必要深入的从代码的角度来学习一下,不妨自己也用Python从零写一个交互式的网络和IP地址计算器,重新造一遍轮子,一来可以温故知新,二来可以帮助我们更深入的了解二进制和十进制在Python里是怎么玩的。该交互式计算器的作用是让用户输入一个合法的IP地址及子网掩码,然后根据用户输入的信息自动给出用户查询的网段的网络IP、广播IP、网段内可用的IP地址数、反掩码以及用户输入的子网掩码对应的“/”格式的掩码位(比如用户输入的掩码是255.255.128.0,计算器会自动在结果中给出/17的掩码位)。
因为是所有网工必须掌握的基本功,为了节约篇幅,下面我只高度概括一下网络和IP地址计算的理论要点,我们重点要关注的是如何在Python中实现它们(所有演示我都将在解释器里实时完成,让读者更清楚的看到十进制和二进制的相互转换在Python中是怎样完成的)大致可以归纳为A,B,C,D,E总共5个点,分述如下:
A.
我们知道任何一个合法的IP地址和子网掩码都可以用32位的二进制(binary)表示,这32位二进制又被分为4个八位位组(octet),比如192.168.1.1用二进制可以写成11000000.10101000.00000001.00000001,这个转换步骤在Python中实现的方法如下:
- 这里我们用字符串自带的split()函数将ip地址(字符串‘192.168.1.1')转换成列表ip_octets,然后创建一个空列表ip_octets_binary,随后用for循环遍历ip_octets里的元素,将它们每个用bin()函数转换成二进制形式,然后一一写入刚才创建的空列表ip_octets_binary里面。
- 关于binary_octet = bin(int(octet)).lstrip('0b'),bin()只能将数据类型为整数的十进制数转换成二进制,因此这里我们要先将字符串用int()转换成整数后再来调用bin()函数,而bin()函数本身会在转化后的二进制数字前面加上'0b',我们必须调用lstrip('0b')将其拿掉,演示如下:
- 再来看ip_octets_binary.append(binary_octet.zfill(8))中的zfill(8),它的作用是自动帮我们填充八位数的二进制数,什么意思呢?比如我们有个IP地址192.168.0.1,它的第三个八位组为0,写成二进制的话应该为00000000,如果我们将0用bin()转换成二进制后会怎么样呢?演示如下:
是不是只得到了一位数的二进制数0?加上zfill(8)后即得到八位组的二进制00000000,效果如下:
同样的代码也适用于子网掩码,比如在Python中要将255.255.255.0这个掩码转换成二进制形式,代码可以这么写:
B.
知道如何在Python里将十进制的IP地址和子网掩码转换成二进制后,我们再来看下如何将二进制的IP地址和子网掩码转换回十进制(代码接续前文):
- 这里只讲一点,在Python中我们可以借助int()函数里的2这个参数将数据类型为字符串的二进制数字转换成数据类型为整数的十进制数字,举例如下:
- 同样的道理,我们可以将二进制形式的子网掩码转换回十进制:
C.
我们知道要算出一个网段内有多少可用的IP地址需要知道该网段的子网掩码以二进制表达时里面有多少个0 (number of zeros,在Python中我们将其赋值给变量no_of_zeros),然后套用公式2 ** no_of_zeros - 2即可算出,比如这里给定的子网掩码255.255.255.0,将其转化为二进制为1111111.1111111.11111111.00000000,总共8个0, 那么2**8-2 = 254,即为我们要的结果,这个运算过程在Python中的计算方式如下(代码接前文):
- 这里我们用abs()这个绝对值函数来计算有多少可用的IP地址,原因是当子网掩码为/32 (255.255.255.255)时,no_of_zeros = 0,如果不用abs()的话, 2 ** 0 - 2 结果为负1,用abs()则可以将其转换成正1, 演示如下:
D.
我们知道网络IP和广播IP是两个很重要的概念,在给定一个IP地址及其子网掩码后,计算该网段的网络IP和广播IP的方法想必大家都知道,即将IP地址和子网掩码分别转换成二进制,然后将两者对比,看子网掩码的二进制有多少个1,那么IP地址的二进制就从左至右保留多少位,剩下的部分全部以0填充,即可得到网络IP的二进制地址,如果剩下部分全部以1填充,则得到广播IP的二进制地址(这里就不画图演示了,这些都是网工最最最基础的知识点,不懂的回去把CCENT或CCNA的书重新翻出来读)。下面我们在Python中演示如何实现找出一个指定IP所在网段的网络IP和广播IP(代码接前文,以前文给定的IP地址192.168.1.1和子网掩码255.255.255.0为例):
- 在使用上面提到的填充0的方法得到了网络IP的二进制地址(11000000101010000000000100000000)后,为了将它转换成四个八位组的十进制形式,这里我们巧用for循环配合range(0,32,8)来将该网络IP的二进制地址切成四段,每段含8个二进制数字,作为元素被依次添加进net_ip_octets这个空列表,最后使用带参数2的int()函数将它们转换成十进制,然后再将这四个十进制数字作为元素依次添加进net_ip_address这个空列表,最后配合".".join()将给列表转化为字符串,即得到了网络IP:192.168.1.0
依葫芦画瓢,从下面这段代码中我们又得到了广播IP: 192.168.1.255
E.
最后我们来谈谈反掩码,所谓反掩码就是将子网掩码的二进制里的1换成0,将0换成1,比如255.255.255.0的二进制为11111111.11111111.11111111.00000000,它的反掩码即为00000000.00000000.00000000.11111111,也就是0.0.0.255。在Python里我们可以这样表示(代码接上文):
最后来看下该交互式的网络和IP地址计算器的最终代码:
#coding=utf-8
import sys
try:
while True: #判断用户输入的IP是否符合规范,如果不规范则while循环反复询问,直到用户输入正确IP地址为止。
ip_address = input("输入要查询的IP地址: ")
ip_octets = ip_address.split('.') #将IP地址用split()转换成列表,该列表有4个元素,分别代表用户输入的IP地址的4个8位字段。
#0.0.0.0/8, 127.0.0.0/8, 169.254.0.0/16以及Class D这些保留IP地址均不是有效的IP
if (len(ip_octets) == 4) and (1 <= int(ip_octets[0]) <= 223) and (int(ip_octets[0]) != 127) and (int(ip_octets[0]) != 169 or int(ip_octets[1]) != 254) and (0 <= int(ip_octets[1]) <= 255 and 0 <= int(ip_octets[2]) <= 255 and 0 <= int(ip_octets[3]) <= 255):
break
else:
print("\n不是有效的IP地址,请重新输入\n")
continue
masks = [255, 254, 252, 248, 240, 224, 192, 128, 0] #将所有有效的子网掩码的十进制数字归纳进一个列表,用于验证用户输入的子网掩码是否合乎规范
while True: #判断用户输入的子网掩码是否符合规范,如果不规范则while循环反复询问,直到用户输入正确子网掩码为止。
subnet_mask = input("输入子网掩码: ")
mask_octets = subnet_mask.split('.') #将子网掩码用split()转换成列表,该列表有4个元素,分别代表用户输入的子网掩码的4个8位字段。
#支持/0 - /32所有子网掩码
if (len(mask_octets) == 4) and (int(mask_octets[0]) in masks) and (int(mask_octets[1]) in masks) and (int(mask_octets[2]) in masks) and (int(mask_octets[3]) in masks) and (int(mask_octets[0]) >= int(mask_octets[1]) >= int(mask_octets[2]) >= int(mask_octets[3])):
break
else:
print("\n不是有效的子网掩码,请重新输入\n")
continue
mask_octets_binary = []
for octet in mask_octets:
binary_octet = bin(int(octet)).lstrip('0b')
#print(binary_octet)
mask_octets_binary.append(binary_octet.zfill(8))
#print(mask_octets_binary)
binary_mask = "".join(mask_octets_binary)
#print(decimal_mask)
no_of_zeros = binary_mask.count("0")
no_of_ones = 32 - no_of_zeros
no_of_hosts = abs(2 ** no_of_zeros - 2) #当掩码为/32时,2的0次方减1等于-1,需要用abs()函数将其转换成正数1.
#print(no_of_zeros)
#print(no_of_ones)
#print(no_of_hosts)
wildcard_octets = []
for octet in mask_octets:
wild_octet = 255 - int(octet)
wildcard_octets.append(str(wild_octet))
#print(wildcard_octets)
wildcard_mask = ".".join(wildcard_octets)
#print(wildcard_mask)
ip_octets_binary = []
for octet in ip_octets:
binary_octet = bin(int(octet)).lstrip('0b')
#print(binary_octet)
ip_octets_binary.append(binary_octet.zfill(8))
#print(ip_octets_binary)
binary_ip = "".join(ip_octets_binary)
#print(binary_ip)
network_address_binary = binary_ip[:(no_of_ones)] + "0" * no_of_zeros
#print(network_address_binary)
broadcast_address_binary = binary_ip[:(no_of_ones)] + "1" * no_of_zeros
#print(broadcast_address_binary)
net_ip_octets = []
for bit in range(0, 32, 8):
net_ip_octet = network_address_binary[bit: bit + 8]
net_ip_octets.append(net_ip_octet)
#print(net_ip_octets)
net_ip_address = []
for each_octet in net_ip_octets:
net_ip_address.append(str(int(each_octet, 2)))
#print(net_ip_address)
network_address = ".".join(net_ip_address)
#print(network_address)
bst_ip_octets = []
for bit in range(0, 32, 8):
bst_ip_octet = broadcast_address_binary[bit: bit + 8]
bst_ip_octets.append(bst_ip_octet)
#print(bst_ip_octets)
bst_ip_address = []
for each_octet in bst_ip_octets:
bst_ip_address.append(str(int(each_octet, 2)))
#print(bst_ip_address)
broadcast_address = ".".join(bst_ip_address)
#print(broadcast_address)
print("\n")
print("该网段的网络地址为: %s" % network_address)
print("该网段的广播地址为: %s" % broadcast_address)
print("该网段可用的IP地址数量为: %s" % no_of_hosts)
print("反掩码: %s" % wildcard_mask)
print("掩码位: %s" % no_of_ones)
print("\n")
print(input())
except KeyboardInterrupt:
print("\n\n程序终止\n")
sys.exit()- 代码前面用来判断用户所输入的IP地址和子网掩码是否合法的部分,我已经在相应位置做了备注帮助大家理解,这里就不再赘述了。
最后运行该程序看效果:
相关推荐
- 戴尔官网保修查询入口(戴尔售后保质期查询)
-
可以按照以下步骤查询戴尔笔记本电脑的保修期:1.打开戴尔官网:https://www.戴尔.com/zh-cn/售后服务/保修政策.html2.点击页面上方的“服务与支持”按钮,进入戴尔的服务支持...
- 手机号邮箱登录入口(手机号邮箱官网)
-
手机163邮箱登录入口如下:163邮箱官网入口:https://smart.mail.163.com/login.htm点击进入登录或者注册邮箱即可。手机浏览器访问进入官网http://www.123...
- sd卡(sd卡无法读取怎么修复)
-
SD卡是大卡,相机用的;普通的手机内存卡,是小卡,正规的名称是macrosd卡,也就是微型SD卡。可以通过卡套转为普通的SD卡的大小。 其实就是大小不同。但手机上的内存卡,人们经常也俗称为SD...
- windows7蓝牙功能在哪里打开
-
点击搜索框在windows7系统主界面点击开始菜单,点击打开搜索框。输入命令输入services.msc后回车,在列表中找到并右击BluetoothSupportS...点击属性选择进入属性菜单,...
-
- 2010激活密钥(microsoft2010激活密钥)
-
步骤/方式1officeprofessionalplus2010:(office专业版)6QFdx-pYH2G-ppYFd-C7RJM-BBKQ8Bdd3G-xM7FB-Bd2HM-YK63V-VQFdKVYBBJ-TRJpB-QFQ...
-
2025-11-19 04:03 off999
- 联想官方刷新bios工具(联想电脑刷新bios)
-
刷新BIOS需要使用联想的官方网站或授权维修中心来进行操作。以下是一些基本步骤:1.访问联想的官方网站,找到BIOS更新程序并下载。在下载过程中,请确保选择与您计算机型号匹配的版本。2.将下载的B...
-
- 苹果ios14系统下载(苹果ios14.1下载)
-
1方法一步骤/方式一打开Appstore。步骤/方式二在搜索栏点击搜索框。步骤/方式三搜索并点击需要下载的软件。步骤/方式四点击获取。步骤/方式五最后验证ID密码即可。1.在应用商店搜索你要下载的应用名称。2.点击下载按钮,如果要求登...
-
2025-11-19 03:03 off999
- office2010怎么免费永久激活密钥
-
用这个试试,一个KMS激活工具可以激活2010到2019的Office自家的目前用的就是这个microsoft6477.moe/1716.html直接使用这个Microsoftoffice2010...
-
- 类似爱加速的国内ip(类似爱加速的app)
-
推荐“V8盒子”。这一款免费无广告的模拟器,不同于其它软件盒子,而是类似于X8沙箱,满足游戏多开,画中画,悬浮球操作,熄屏后台运行等多功能的沙箱盒子.支持一键root,一键安装xposed框架,能在安卓/苹果手机上运行多个安卓/ios虚拟系...
-
2025-11-19 02:03 off999
- 阿里旺旺手机客户端(阿里旺旺手机app)
-
手机淘宝的旺旺在打开商品后,会看到左下角有个旺旺的图标,点击就可以联系了。 阿里旺旺是将原先的淘宝旺旺与阿里巴巴贸易通整合在一起的一个新品牌。它是淘宝和阿里巴巴为商人量身定做的免费网上商务沟通软件,...
- 最纯净的pe装机工具(pe工具哪个纯净)
-
U盘装系统步骤:1.制作U盘启动盘。这里推荐大白菜U盘启动盘制作工具,在网上一搜便是。2.U盘启动盘做好了,我们还需要一个GHOST文件,可以从网上下载一个ghost版的XP/WIN7/WIN8系统,...
- 装一个erp系统多少钱(wms仓库管理软件)
-
现在主流有客户端ERP和云端ERP两种客户端通常一次买断,价格在万元左右,但是还有隐性费用,你需要支付服务器、数据管理员,此外如果系统需要更新维护,你还需要支付另外一笔不菲的费用。云端ERP:优势...
- cad2014序列号和密钥永久(autocad2014序列号和密钥)
-
1在cad2014中修改标注样式后,需要将其保存2单击“样式管理器”按钮,在弹出的窗口中选择修改后的标注样式,然后单击“设置为当前”按钮,再单击“保存当前样式”按钮,将其保存为新的样式名称3为了...
- qq修改密保手机号(qq修改密保手机号是什么意思)
-
QQ更改绑定的手机号码操作步骤如下:1、打开手机主界面,找到“QQ”软件点击打开。2、输入正确的QQ账户和密码登录到qq主界面。3、点击左上角的头像“图片”,进入到个人中心界面。4、进入到个人中心界面...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
python入门到脱坑 输入与输出—str()函数
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
慕ke 前端工程师2024「完整」
-
失业程序员复习python笔记——条件与循环
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
