上下文: 我正在尝试捕获某些MQTT消息,然后将其记录的程序。在执行此操作时,遇到一个奇怪的问题,需要帮助。
在传入的消息中,我得到一个以base64编码的字符串。我的程序尝试对二进制数据进行解码和解析,以找出数据包的某些标头。我的代码如下所示:
result = base64.standard_b64decode("AO/Nq4lnRSMBZXMnLHcKXhSObYxiFvY=")
结果的输出如下:
b"\x00\xef\xcd\xab\x89gE#\x01es',w\n^\x14\x8em\x8cb\x16\xf6"
如果使用nodeJS实现执行相同的操作,则输出将大不相同:
<Buffer 00 ef cd ab 89 67 45 23 01 65 73 27 2c 77 0a 5e 14 8e 6d 8c 62 16 f6>
我阅读了堆栈溢出中的其他一些链接,但不明白为什么存在这种差异。链接NodeJS base64 Vs Python base64的有效点指向已完成的编码,因此Python在这里所做的工作没有错。
进一步阅读后,我发现了另一个技巧,其中使用了binascii函数。因此,如果应用此逻辑,我的输出看起来就像NodeJS的输出!
import binascii
binascii.hexlify(result)
b'00efcdab89674523016573272c770a5e148e6d8c6216f6'
现在我的输出看起来像我想要的。但是,还有另一个新问题。 base64解码的输出为b'\ x00'格式,而hexlify的输出为b'0'。由于存在这种差异,因此我无法运行代码的另一部分,该部分将逐个字节地拆分此输出,以根据数据包的标头以不同的格式执行struct.unpack。
我能得到什么帮助吗?
答案 0 :(得分:1)
如果我理解得很好,您会对字节的Python格式感到困惑。
基本上,当在Python中显示一个字节时,如果此字节与ASCII字符匹配,则使用该字符代替数字值。结果在Python和NodeJS中实际上是相同的,只是表示形式有所不同。
您可以通过对齐两个表示来检查它:
b" \x00\xef\xcd\xab\x89 g E #\x01 e s ' , w \n ^\x14\x8e m\x8c b\x16\xf6"
<Buffer 00 ef cd ab 89 67 45 23 01 65 73 27 2c 77 0a 5e 14 8e 6d 8c 62 16 f6>
如您所见,除了:
67 -> g
45 -> E
23 -> #
65 -> e
73 -> s
27 -> '
2c -> ,
0a -> \n
5e -> ^
6d -> m
事实是,上面显示的每个十六进制值都与ASCII表中的一个字符匹配。
您可以在Python解释器中轻松地对其进行验证(ord
提供给定字符的ascii代码,hex
将其转换为十六进制表示形式):
>>> hex(ord('g'))
'0x67'
>>> hex(ord('E'))
'0x45'
>>> hex(ord('#'))
'0x23'
最后,您甚至可以在几行Python中获得与NodeJS完全相同的表示形式:
>>> bytes = b"\x00\xef\xcd\xab\x89gE#\x01es',w\n^\x14\x8em\x8cb\x16\xf6"
>>> print('<Buffer {}>'.format(' '.join([format(c, '02x') for c in bytes])))
<Buffer 00 ef cd ab 89 67 45 23 01 65 73 27 2c 77 0a 5e 14 8e 6d 8c 62 16 f6>
答案 1 :(得分:0)
base64.standard_b64decode
返回一个bytes
对象,该对象是不可变的单字节序列。这由b
之前的"
字母表示。
来自docs:
字节字面量始终以
'b'
或'B'
为前缀;它们产生bytes
类型的实例,而不是str
类型的实例。它们只能包含ASCII字符;数值等于或大于128的字节必须用转义符表示。
您在这里看到的是bytes
对象的ASCII表示形式,而不是字符串。
要将bytes
对象转换为类似于从nodeJS得到的结果的字符串,可以使用bytes
对象方法hex
:
import base64
result = base64.b64decode(b"AO/Nq4lnRSMBZXMnLHcKXhSObYxiFvY=")
print(result.hex())
>>> 00efcdab89674523016573272c770a5e148e6d8c6216f6