解码 TCP 连接的有效负载:“utf-8”编解码器无法解码位置 4 中的字节 0x87:无效起始字节

时间:2021-07-09 14:25:28

标签: python encoding utf-8 character-encoding ascii

我通过 TCP 从传感器节点发送到我的 TCP 服务器。原始接收数据如下所示:

<块引用>

b'A\x10Vu\x87%\x00x\x0c\xc7\x03\x01\x00\x00\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00'

尝试使用 utf-8 对其进行解码时,我收到以下错误。 代码:

my_variable = b'A\x10Vu\x87%\x00x\x0c\xc7\x03\x01\x00\x00\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00'

print(my_variable.decode('utf-8'))

错误:

<块引用>

print(my_variable.decode('utf-8')) UnicodeDecodeError: 'utf-8' codec 无法解码位置 4 中的字节 0x87:无效起始字节

所以问题是 Payload 包含非 ascii 格式的字符,显然。

我怎样才能将此有效载荷解码为某物。人类可读?

负载描述可以是 found here on p32。 p20 显示了一个 tcp 连接示例,但没有解码有效负载。

3 个答案:

答案 0 :(得分:0)

基于文档不是 human readable 并且您不应该对其进行解码,但您应该编写特殊代码将每个值从十六进制转换为整数,并最终将其转换为带有额外值的字​​符串 - 即。版本号中的点。

这里是有效载荷起始值的代码

data = b'A\x10Vu\x87%\x00x\x0c\xc7\x03\x01\x00\x00\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00'

ID = data[:6].hex()
print('ID:', ID)

hardware = data[6]
if hardware == 1:
    hardware = 'NBSN95'
print('hardware version:', hardware)

software = data[7]
print('software version (raw):', software)

software = '.'.join(list(str(software)))
print('software version:', software)

battery = data[8:10].hex()
print('battery (raw):', battery)

battery = int(battery, 16)
print('battery:', battery, 'mV =', battery/1000, 'V')

signal = data[10]
print('signal (raw):', signal)    

if signal == 0:
    signal = '-113dBm or less'
elif signal == 1:
    signal = '-111dBm'
elif 2 <= signal <= 30:
    signal = '-109dBm ... -53dBm'
elif signal == 31:     
    signal = '-51dBm or greater'
elif signal == 99:
    signla = 'Not known or not detectable'
print('signal:', signal)    
    
temp = data[11:13].hex()    
print('temperature (raw):', temp)

temp = int(temp, 16)
if temp & 0xFC00 == 0:
    temp = temp/10
elif temp & 0xFC00 == 1:
    temp = (temp-65536)/10
print('temperature:', temp, 'degree')

结果:

ID: 411056758725
hardware version: 0
software version (raw): 120
software version: 1.2.0
battery (raw): 0cc7
battery: 3271 mV = 3.271 V
signal (raw): 3
signal: -109dBm ... -53dBm
temperature (raw): 0100
temperature: 25.6 degree

答案 1 :(得分:0)

您可以在 Python 提示中找到答案。事实上,我是从 dir(my_variable):

开始探索的
my_variable = b'A\x10Vu\x87%\x00x\x0c\xc7\x03\x01\x00\x00\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00'
# dir(my_variable)
my_variable.hex
<块引用>
<built-in method hex of bytes object at 0x00000232BDF129F0>
help(my_variable.hex)            # truncated
<块引用>
Help on built-in function hex:

hex(...) method of builtins.bytes instance
    Create a str of hexadecimal numbers from a bytes object.
my_variable.hex()
<块引用>
'41105675872500780cc7030100000000260000000000000000'

答案 2 :(得分:0)

数据是原始字节数据,不应被解码。相反,使用 struct 模块将原始字节解包为字节和数据字。 spec(第 22 页)表示每个字段的字节数:

packet layout

struct 模块还有一个优点,您不必手动计算每个字段的偏移量,如果解包模式与数据长度不匹配,它将捕获错误。

注意2字节版本是硬件版本字节和软件版本字节,所以我用BB(2字节)分别提取出来。温度被记录为二进制补码,因此我使用 h(有符号的 16 位值)作为它们。还要注意数据是大端的,所以使用 >

另请参阅 struct - Format String 文档。

import struct
from datetime import datetime
from pytz import UTC

data = b'A\x10Vu\x87%\x00x\x0c\xc7\x03\x01\x00\x00\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00'

devid,hw,sw,bat,ss,mod,t1,dii,adc,t2,h,ts = struct.unpack('>6sBBHBBhBHhHL',data)

# fields that needed processing are done in the f-strings below
print(f"DeviceID={devid.hex()} HW={hw} SW={'.'.join(str(sw))}\n"
      f"BAT={bat:.3f}mV SignalStrength={-113+2*ss}dBm Mode={mod} Temp={t1/10}\N{DEGREE CELSIUS}\n"
      f"Door={dii==0x80} ADC={adc}mv Temp2={t1/10:.1f}\N{DEGREE CELSIUS} Humidity={h/10:.1f}%\n"
      f"Timestamp={datetime.fromtimestamp(ts,UTC)}")

输出:

DeviceID=411056758725 HW=0 SW=1.2.0
BAT=3.271V SignalStrength=-107dBm Mode=1 Temp=0.0℃
Door=False ADC=38mv Temp2=0.0℃ Humidity=0.0%
Timestamp=1970-01-01 00:00:00+00:00
相关问题