使用它并不是那么简单struct
,因为在将其添加到结构之前,您必须知道 IPv6 地址的正确字节值。'2001::1' 是一种文本表示,它远不能为您提供这些值:您必须将字符串拆分:
为打包在结构中。当然,在 IPv6 字符串表示中存在一些极端情况和特殊语法,您必须考虑到这一点。
幸运的是,Python 已经在 . ipaddress
标准库的模块。
只需 import ipaddress
,为包的第一部分格式化结构,并将其与 IPv6Address Python 中的“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 地址是否会有效——无论读取什么代码,它都将与您正在写入的代码超级耦合。如果您只是将它存储到一个文件中以供您控制下的 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)
如果需要,在服务器端表示数字时使用。