繁体   English   中英

解码 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'))

错误:

打印(my_variable.decode('utf-8'))UnicodeDecodeError:'utf-8'编解码器无法解码位置4的字节0x87:无效的起始字节

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

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

可以在 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模块将原始字节解包为字节和数据字。 规范(第 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM