如何在 python 中使用“struct”库发送 IPv6 地址

Posted

技术标签:

【中文标题】如何在 python 中使用“struct”库发送 IPv6 地址【英文标题】:How to send an IPv6 address with the 'struct' library in python 【发布时间】:2022-01-12 14:31:55 【问题描述】:

我正在寻求您的帮助,因为我被同样的问题困扰了 3 天。 如果我有:

Value1 = 0, Value2 = 3.10 and IPv6 = '2001::1'

我想用这个命令打包所有 3 个值:package = struct.pack(*format*, value1, value2, IPv6)

我的问题是:我不知道我可以使用 C 类型中的哪些格式字符来打包 IPv6 并保留其 16 个字节。 我知道我可以将format = 'i f ?' 与 i 一起用于整数 / f 用于浮点数,但我需要找到用什么来替换“?”是IPv6地址的C类型格式字符,用于打包这三个值。

拜托,有人可以帮助我吗?

【问题讨论】:

【参考方案1】:

为此使用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)

【讨论】:

您好,首先感谢您的回答。这样做的目的是打包来自虚拟传感器的一些数据,并将带有这些强制值的数据包发送到带有 TCP 套接字的服务器。明天我会试试你的建议,如果可行我会再次联系。 是的 - 你是在我提到的“具有低级协议的自定义服务器”的情况下。固定尺寸的包装可能确实有帮助——如果“3.10”真的是一个传感器测量值,那么将它包装成一个浮点数是有意义的。用字段编写一个类。处理二进制有效负载的“打包”和“解包”方法可能会有所帮助 - 它们在客户端和服务器端都使用这个更高级别的代码。 你好我今天早上测试了你的方法。但我不知道如何解压有效载荷。你能帮帮我吗? 我用sn-p完成了答案,包括拆包部分。请注意如何使用此模型,有效负载中使用的类型和值必须在源本身中进行硬编码,并且人类不可读:因此我强调使用更高级别的协议,该协议要么是无模式的,要么可以与模式一起发送数据 - 或将代码/解码信息放在适当的类中,并在客户端和服务器端重用此类的代码。 非常感谢!一切顺利。您的方法有效,我找到的解决方案也有效。我使用字典来封装变量。我注意到这篇文章已经解决了。

以上是关于如何在 python 中使用“struct”库发送 IPv6 地址的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 Modbus TCP 使用“struct.pack”类型发送?

在 python 中使用 AMQP 库发送和接收消息

Python struct作为网络数据包(未知字节序列)

Python to C#:如何格式化套接字数据?

Python struct模块

msgpack可以提供更好的性能和相同的python的struct.pack()功能吗?