背景
互联网上分布着很多设备,如电脑、手机、智能手表等。设备与设备之间会互相通信,如你给朋友发送一条微信语音信息,其实就是你的手机在与朋友的手机进行通信。
但是,这条信息为什么会准确到达你朋友的手机,而不是其他设备?这是因为网络上的每台设备都有一个唯一的网络地址。如果把网络信息看作日常生活中的信件,网络地址就是信件上的收件人地址,有了这个地址,信息就能准确到达网络上的某一设备。
网络地址有不同类型,如 MAC 地址、IP 地址、URL 等,本关针对的是 IP 地址。IP 地址目前主要有两个版本:IPv4 和 IPv6,本关所说 IP 地址是指 IPv4。
关于网络的相关知识,在后续还会进一步学习。
IP 地址用 32 位二进制表示,如 10101000 00010000 01111111 11111101(中间的空格是为了方便阅读,实际是没有空格的)。但二进制并不方便人类阅读,所以在使用时,IP 地址常采用点分十进制表示形式,即把 32 位二进制分为 4 个字节,每个字节转换成一个十进制数,再用点号将四个十进制数连接起来,如下图所示。
2 位的 IP 地址由两部分组成,前面若干位是网络号,用于标识设备位于的子网络,剩下的若干位是主机号,是设备在子网络中的编号。要从一个 IP 地址中提取网络号和主机号,需要用到子网掩码。子网掩码也用 32 位二进制表示,且前面全部为 1,后面全部为 0,如 11111111 11111111 11000000 00000000,对应的点分十进制形式为 255.255.192.0。
假设现有点分十进制形式的 IP 地址和子网掩码,则利用子网掩码提取 IP 地址中的网络号和主机号过程如下:
1)将 IP 地址和子网掩码转换成 32 位二进制形式,分别用 a 和 b 表示;
2)令 c=a∧b,将 c 转换成点分十进制形式,即得网络号;
3)令 d=a∧¬b,将 d 转换成点分十进制形式,即得主机号。
例如,IP 地址为 168.16.127.253、子网掩码为 255.255.192.0,则计算过程如下:
1)IP 地址对应的二进制是 10101000 00010000 01111111 11111101,子网掩码对应的二进制是 11111111 11111111 11000000 00000000;
2)10101000 00010000 01111111 11111101 ∧ 11111111 11111111 11000000 00000000 = 10101000 00010000 01000000 00000000,对应的点分十进制形式是 168.16.64.0,这是网络号;
3)10101000 00010000 01111111 11111101 ∧ ¬11111111 11111111 11000000 00000000 = 00000000 00000000 00111111 11111101,对应的点分十进制形式是 0.0.63.253,这是主机号。
本关任务就是编程实现此过程。
相关知识
提示:注意将这个问题分解成一些小问题,如进制转换、逻辑运算等,并封装成函数。
此外,使用split函数和join函数能够简化一些操作,示例如下:
s = 'a-b-c-d'
L = s.split('-') #split函数的功能是根据给定分割符对字符串进行分割
print(L) #如分割符为'-',则'a-b-c-d'被分割为['a', 'b', 'c', 'd']
L = ['a', 'b', 'c', 'd']
s = '-'.join(L) #join函数功能与split相反,是对若干字符串进行连接
print(s) #如连接符为'-',则['a', 'b', 'c', 'd']被连接为'a-b-c-d'
编程要求
在 Begin-End 区间实现parseIP(ip, mask)函数,说明如下:
1)参数 ip和mask是字符串,分别表示点分十进制形式的 IP 地址和子网掩码;
2)函数有两个返回值,依次是点分十进制形式的网络号和主机号;
3)允许使用 Python 提供的进制转换函数。
测试说明
例如,测试集 1 的输入为:
168.16.127.253
255.255.192.0
测试集 1 的输出为:
网络号: 168.16.64.0
主机号: 0.0.63.253
代码:
########## Begin ##########
def AND(a,b):
c = ''
for i,j in zip(a,b):
if i==j and i=='1':
c = c + '1'
else:
c = c + '0'
return c
def OR(a,b):
c = ''
for i,j in zip(a,b):
if i==j and i=='0':
c = c + '0'
else:
c = c + '1'
return c
def NOT(a):
c = ''
for i in a:
if i=='0':
c = c + '1'
else:
c = c + '0'
return c
def XOR(a,b):
c = ''
for i,j in zip(a,b):
if i==j:
c = c + '0'
else:
c = c + '1'
return c
def hexcon(ip):
# 将 IP 地址和子网掩码转换成 32 位二进制形式
lip = ip.split('.')
s = ''
for i in lip:
lb = [j for j in bin(eval(i))[2:]]
if len(lb)<8:
for j in range(8-len(lb)):
lb.insert(0, '0')
s = s + ''.join(lb)
return s
def bin32_to_dec(bin_wlno):
# 32位的二进制转换成十进制整数
L = []
for i in range(0,len(bin_wlno),8):
dec_wlno = int(bin_wlno[i:i+8],2)
L.append(str(dec_wlno))
return '.'.join(L)
def parseIP(ip,mask):
bin_ip = hexcon(ip)
bin_mask = hexcon(mask)
# 二进制网络号,令 c=a∧b,
bin_wlno = AND(bin_ip, bin_mask)
# 将 c 转换成点分十进制形式,即得网络号
netID = bin32_to_dec(bin_wlno)
# 二进制主机号,令 d=a∧¬b
bin_zjno = AND(bin_ip,NOT(bin_mask))
# 将 d 转换成点分十进制形式,即得主机号
hostID = bin32_to_dec(bin_zjno)
return netID,hostID
########## End ##########
ip = input() #IP地址
mask = input() #子网掩码
netID, hostID = parseIP(ip, mask)
print('网络号:', netID) #网络号
print('主机号:', hostID) #主机号