Python缓冲区解码

时间:2015-03-13 09:34:33

标签: python buffer decode encode

我有一个从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 size\n",p.size());
    }

类型是:

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

发送和接收的数据现在长达40个字节。

Edit2:正确的解决方案是

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

2 个答案:

答案 0 :(得分:2)

我认为struct正是您所寻找的。无论如何,你必须找出序列化的数据格式。它不是一个发送的C / C ++结构,而是(hopefilly)一个很好描述的序列化格式,可能是binaray。重要的主题是小/大的endianess,double的大小,int的大小和填充。

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

标准尺寸需要36个字节

>>> from struct import *
>>> a='\x00\x00\x00\x01'*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)
>>>

编辑:解压缩变量,命名为tuple和class

直接解压缩到您的变量

from struct import unpack 
b = "\x00\x00\x00\x05\x00\x00\x00\x2a"

x, y = unpack('!ii', b)
print x
print y

解压缩到命名元组

from struct import unpack 
from collections import namedtuple
b = "\x00\x00\x00\x05\x00\x00\x00\x2a"

Point = namedtuple('Point', 'x, y')

p = Point._make(unpack("!ii", b))
print p.x
print p.y

记住:元组属性是只读的

解压缩并使课程

from struct import unpack 
b = "\x00\x00\x00\x05\x00\x00\x00\x2a"

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

答案 1 :(得分:2)

我也使用了struct unpacking(并且每次都必须搜索字符代码),直到我学会了使用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)