解码 TCP 连接的有效负载:'utf-8' 编解码器无法解码位置 4 中的字节 0x87:起始字节无效
Decode Payload of TCP connection: 'utf-8' codec can't decode byte 0x87 in position 4: invalid start byte
我正在通过 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
can't decode byte 0x87 in position 4: invalid start byte
所以问题是有效载荷包含非 ascii 格式的字符,显然。
我怎样才能将这个有效载荷解码成某物。人类可读?
负载描述可以是found here on p32。 p20 显示了一个 tcp 连接示例,但没有解码有效负载。
基于文档不是 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
您可以在 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'
数据是原始字节数据,不应解码。相反,使用 struct
module to unpack the raw bytes into bytes and words of data. The spec(第 22 页)指示每个字段有多少字节:
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
我正在通过 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 can't decode byte 0x87 in position 4: invalid start byte
所以问题是有效载荷包含非 ascii 格式的字符,显然。
我怎样才能将这个有效载荷解码成某物。人类可读?
负载描述可以是found here on p32。 p20 显示了一个 tcp 连接示例,但没有解码有效负载。
基于文档不是 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
您可以在 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'
数据是原始字节数据,不应解码。相反,使用 struct
module to unpack the raw bytes into bytes and words of data. The spec(第 22 页)指示每个字段有多少字节:
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