解析IP地址

背景
  互联网上分布着很多设备,如电脑、手机、智能手表等。设备与设备之间会互相通信,如你给朋友发送一条微信语音信息,其实就是你的手机在与朋友的手机进行通信。
  但是,这条信息为什么会准确到达你朋友的手机,而不是其他设备?这是因为网络上的每台设备都有一个唯一的网络地址。如果把网络信息看作日常生活中的信件,网络地址就是信件上的收件人地址,有了这个地址,信息就能准确到达网络上的某一设备。
  网络地址有不同类型,如 MAC 地址、IP 地址、URL 等,本关针对的是 IP 地址。IP 地址目前主要有两个版本:IPv4 和 IPv6,本关所说 IP 地址是指 IPv4。
  关于网络的相关知识,在后续还会进一步学习。
  IP 地址用 32 位二进制表示,如 10101000 00010000 01111111 11111101(中间的空格是为了方便阅读,实际是没有空格的)。但二进制并不方便人类阅读,所以在使用时,IP 地址常采用点分十进制表示形式,即把 32 位二进制分为 4 个字节,每个字节转换成一个十进制数,再用点号将四个十进制数连接起来,如下图所示。
  
 解析IP地址
 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)  #主机号
上一篇:[转]C++ STL list的初始化、添加、遍历、插入、删除、查找、排序、释放


下一篇:位运算查缺补漏