蟒蛇缓冲区解码



我有一个从C++程序发送的UDP包,我必须用Python读取它。我设法收到了UDP包,但不幸的是它被编码了。C++数据具有以下形式

struct packet{
    double arg1
    double arg2
    double arg3
    double arg4
    int16_t arg5
};

我收到的数据总共有 42 个字节长(与发送的数据长度相同)。也许数据在发送之前也略有变化,但我仍在努力弄清楚。所以我的问题是:让我们假设发送数据的结构与上述完全相同。如何从缓冲区中读出它?(顺便说一句。我正在使用Python 2.7.9)

谢谢已经

编辑:我发现了一些关于结构的东西

void Send(const CrazyFliePacket& packet)
    {
        FMA::ByteBuffer p = 
            FMA::Encode((PACKET_TYPE)FMA_PACKET_TYPES::CRAZYFLIE) + 
            FMA::Encode((PACKET_VERSION)0) +
            FMA::Encode(_seq++) + 
            packet.Encode();
        _server->SendPacket(p.data(),p.size());
        printf("Packet sent with %i bytes sizen",p.size());
    }

类型有:

typedef unsigned short PACKET_TYPE;
typedef unsigned short PACKET_VERSION;
uint16_t _seq;

发送和接收的数据现在长度为 40 字节。

编辑2:正确的解决方案是

print struct.unpack('<HHhddddh', data)

我认为结构是你正在寻找的。无论如何,您必须找出序列化的数据格式。发送的不是 C/C++ 结构,而是(希望)一种描述良好的序列化格式,可能是 binaray。重要的主题是小/大字节序、双精度大小、整数大小和填充。

from struct import *
arg1, arg2, arg3, arg4, arg5 = unpack('!ddddi', buffer)

标准大小需要 36 字节

>>> from struct import *
>>> a='x00x00x00x01'*9
>>> unpack('>ddddi', a)
(2.1219957915e-314, 2.1219957915e-314, 2.1219957915e-314, 2.1219957915e-314, 1)
>>> unpack('<ddddi', a)
(7.291122046717944e-304, 7.291122046717944e-304, 7.291122046717944e-304, 7.291122046717944e-304, 16777216)
>>> unpack('!ddddi', a)
(2.1219957915e-314, 2.1219957915e-314, 2.1219957915e-314, 2.1219957915e-314, 1)
>>>

编辑:解压缩到变量,命名元组和类

直接解压缩到变量

from struct import unpack 
b = "x00x00x00x05x00x00x00x2a"
x, y = unpack('!ii', b)
print x
print y

解压缩到命名元组

from struct import unpack 
from collections import namedtuple
b = "x00x00x00x05x00x00x00x2a"
Point = namedtuple('Point', 'x, y')
p = Point._make(unpack("!ii", b))
print p.x
print p.y

记住:元组属性是只读

解压缩和启动类

from struct import unpack 
b = "x00x00x00x05x00x00x00x2a"
class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
p = Point(*unpack('!ii', b))
print p.x
print p.y

我也使用结构体解包(并且每次都必须搜索字符代码),直到我学会了使用 ctypes 做同样的事情。我不知道哪一个执行得更快,但我知道我可以翻译哪一个,只需查看 C 定义即可毫无问题。

from ctypes import LittleEndianStructure, BigEndianStructure, c_int16, c_double, sizeof
#there are bit explicit types if you want to fix the size, like c_int8/16/32/64
class Packet(LittleEndianStructure): # replace by BigEndian as needed
    _fields_ = [
        ("arg1", c_double),
        ("arg1", c_double),
        ("arg3", c_double),
        ("arg4", c_double),
        ("arg5", c_int16)
        ]
    _pack_=1 # comment this or not depending on padding
mypacket = Packet.from_buffer_copy(payload)

对我来说,它更容易阅读,并且它的优点是为我提供了一个收集所有数据并可以按名称访问的对象

print(mypacket.arg1)

最新更新