为此使用struct 并不是那么简单,因为在将其添加到结构之前,您必须知道IPv6 地址的正确字节值。
'2001::1' 是一个文本表示,它远不能为您提供这些值:您必须在 : 上拆分字符串,用“0”替换缺失值,然后您将拥有 4 个 16 位要打包在结构中的数字列表。当然,在 IPv6 字符串表示中存在一些极端情况和特殊语法,您必须考虑到这一点。
幸运的是 Python 已经为你处理好了。 ipaddress 标准库的模块。
只需导入ipaddress,格式化包的第一部分的结构并将其与 IPv6Address 中的“packed”属性连接起来 Python 会自动为您生成:
import struct
import ipaddress
Value1 = 0
Value2 = 3.10
IPv6 = '2001::1'
payload = struct.pack("if", (Value1, Value2)) + ipaddress.ip_address(IPv6).packed
然而,我想知道以这种方式简单地将 int 和 float 与 IP 地址一起打包是否有效 - 无论读取此代码的任何代码都将是 super em> 加上您正在编写的代码。
如果您只是将它存储到一个文件中以供您控制下的 Python 程序读回,只需使用 pickle 代替。如果您打算通过网络将这些值发送到非 Python 程序,那么像 JSON 这样的无模式文本传输方式可能会简单得多。
如果你真的想要存储这些,并且只有这些,为了节省空间,以紧凑的方式存储,它们有数万个,它们将被相同的读回程序:尝试 numpy 数组。它们会处理每种对象类型的紧凑二进制表示,并且可以读取和写入二进制文件,而 numpy 会为您处理记录偏移量。
我能看到的唯一用例是,如果您有一个不受您控制的低级协议中的程序,该协议将完全期望这种记录格式。由于您正在推测如何创建有效负载,并试图将“3.10”作为浮点值传达,因此情况似乎并非如此。谈到这一点,“3.10”或其他数字可能不会像这样的结构良好形成的 2 位十进制数字值往返,因为浮点数在内部是如何表示的。我建议你在那里回顾一下你的目标和需求,不要让事情过于复杂。
要解压,更简单的方法是使用 struct 仅恢复数值,并将剩余的 16 个字节传回 ip_address 工厂函数 - 它会自动创建一个 IPv6 对象,该字符串表示对人类友好“2001::1”。
我在交互式提示中键入“往返”:
In [30]: import struct, ipaddress
In [31]: x = ipaddress.ip_address('2001::1')
In [32]: v1 = 2;v2 = 3.10
In [33]: payload = struct.pack(">if",v1, v2) + x.packed
In [34]: print(payload)
b'\x00\x00\x00\x02@Fff \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
In [35]: v3, v4, nx = struct.unpack(">if", aa[:-16]) + (ipaddress.ip_address(aa[-16:]),)
In [36]: print(v3, v4, nx)
2 3.0999999046325684 2001::1
需要注意两点:在结构格式化字符串上添加>前缀,以确保编码其内容时的字节顺序,
并且如上所述,“3.10”值不会作为“漂亮的小数点后两位”值往返。如果需要,在服务器端表示数字时使用round(number, 2)。