tft每日頭條

 > 圖文

 > 用python編寫一個計算器程序

用python編寫一個計算器程序

圖文 更新时间:2024-12-23 22:52:13

今天從Python的角度來聊下計算機網絡這行基礎中的基礎的話題:網絡和IP地址計算(注:本文裡的IP指的是IPv4,不涉及IPv6)。相信幾乎每位網工讀者在平時的工作和學習中都用過類似下圖的在線網絡和IP地址計算器吧:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)1

這類前人(或者說碼農們)造出的輪子的确很好用,但是很少有網工明白它們背後的工作原理(也就是代碼是怎麼寫出來的)。作為有志成為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中實現的方法如下:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)2

  • 這裡我們用字符串自帶的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')将其拿掉,演示如下:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)3

  • 再來看ip_octets_binary.append(binary_octet.zfill(8))中的zfill(8),它的作用是自動幫我們填充八位數的二進制數,什麼意思呢?比如我們有個IP地址192.168.0.1,它的第三個八位組為0,寫成二進制的話應該為00000000,如果我們将0用bin()轉換成二進制後會怎麼樣呢?演示如下:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)4

是不是隻得到了一位數的二進制數0?加上zfill(8)後即得到八位組的二進制00000000,效果如下:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)5

同樣的代碼也适用于子網掩碼,比如在Python中要将255.255.255.0這個掩碼轉換成二進制形式,代碼可以這麼寫:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)6

B.

知道如何在Python裡将十進制的IP地址和子網掩碼轉換成二進制後,我們再來看下如何将二進制的IP地址和子網掩碼轉換回十進制(代碼接續前文):

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)7

  • 這裡隻講一點,在Python中我們可以借助int()函數裡的2這個參數将數據類型為字符串的二進制數字轉換成數據類型為整數的十進制數字,舉例如下:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)8

  • 同樣的道理,我們可以将二進制形式的子網掩碼轉換回十進制:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)9

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中的計算方式如下(代碼接前文):

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)10

  • 這裡我們用abs()這個絕對值函數來計算有多少可用的IP地址,原因是當子網掩碼為/32 (255.255.255.255)時,no_of_zeros = 0,如果不用abs()的話, 2 ** 0 - 2 結果為負1,用abs()則可以将其轉換成正1, 演示如下:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)11

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為例):

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)12

  • 在使用上面提到的填充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

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)13

E.

最後我們來談談反掩碼,所謂反掩碼就是将子網掩碼的二進制裡的1換成0,将0換成1,比如255.255.255.0的二進制為11111111.11111111.11111111.00000000,它的反掩碼即為00000000.00000000.00000000.11111111,也就是0.0.0.255。在Python裡我們可以這樣表示(代碼接上文):

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)14

最後來看下該交互式的網絡和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地址和子網掩碼是否合法的部分,我已經在相應位置做了備注幫助大家理解,這裡就不再贅述了。

最後運行該程序看效果:

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)15

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)16

用python編寫一個計算器程序(用Python開發一個交互式網絡和IP地址計算器)17

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved