代码之家  ›  专栏  ›  技术社区  ›  Mikhail Venkov

将字节数组从VARBINARY(16)列转换为IP地址

  •  2
  • Mikhail Venkov  · 技术社区  · 7 年前

    cnxn = pyodbc.connect('DRIVER={Vertica};SERVER=localhost;DATABASE=db;UID=user;PWD=pw')
    cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf-8')
    cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-8')
    cnxn.setencoding(str, encoding='utf-8')
    cnxn.setencoding(unicode, encoding='utf-8')
    cur = cnxn.cursor()
    cur.execute("SELECT * FROM schema.table LIMIT 3")
    

    for row in cur:
        print row
    

    大多数字段返回得很好-unicode文本、数字或日期时间。然而,对于存储IP地址的字段,我得到以下信息:

    bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\no\x19\\')
    

    如何将其转换为文本?

    谢谢

    2 回复  |  直到 7 年前
        1
  •  3
  •   mauro    7 年前

    我知道有一个公认的答案,但。。。对于所有其他人:

    首先要做的是检查fine SQL参考手册。在本例中,您将发现一个内置函数,用于将表示为VARBINARY列的IPv6地址转换为字符串。

    更简单、更快:

    SELECT V6_NTOA(your_column_here) ;
    
        2
  •  1
  •   Gord Thompson    7 年前

    VARBINARY(16)是128位,这恰好是IPv6地址的正确大小。样本数据解码为

    0000:0000:0000:0000:0000:ffff:0a6f:195c
    

    和维基百科文章中关于IPv6的“IPv4映射IPv6地址”小节(参考: here )表示这样的地址是映射到IPv6格式(128位)的IPv4地址(32位)。

    ::ffff:10.111.25.92
    

    我们可以从原始数据生成上面的字符串表示 bytearray 使用如下函数的数据:

    def bytes_to_ip_address(byte_array):
        if byte_array[0:12] == bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'):
            return '{0}.{1}.{2}.{3}'.format(byte_array[12], byte_array[13], byte_array[14], byte_array[15])
        else:
            return ':'.join(['{0:02x}{1:02x}'.format(byte_array[i], byte_array[i + 1]) for i in range(0, len(byte_array), 2)])
    
    
    if __name__ == '__main__':
        # examples
        fld = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\no\x19\\')
        print(bytes_to_ip_address(fld))  # 10.111.25.92
        fld = bytearray(b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\no\x19\\')
        print(bytes_to_ip_address(fld))  # 0100:0000:0000:0000:0000:ffff:0a6f:195c
    

    或者,使用Python3,我们可以使用 ipaddress 模块:

    import ipaddress
    
    
    def bytes_to_ip_address(byte_array):
        ip6 = ipaddress.IPv6Address(bytes(byte_array))
        ip4 = ip6.ipv4_mapped
        if ip4 == None:
            return str(ip6)
        else:
            return str(ip4)
    
    
    if __name__ == '__main__':
        # examples
        fld = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\no\x19\\')
        print(bytes_to_ip_address(fld))  # 10.111.25.92
        fld = bytearray(b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\no\x19\\')
        print(bytes_to_ip_address(fld))  # 100::ffff:a6f:195c