Python中未指定的字节长度

时间:2012-03-05 11:45:04

标签: python struct

我正在为P2P应用程序编写一个客户端,协议的规范说每个数据包的标头应该具有特定字节长度的每个字段,如下所示:

Version: 1 Byte 
Type: 1 Byte
Length: 2 Bytes
And then the data

我已经有了打包和解包标题字段的方法(我认为)像这样:

packed = struct.pack('cch' , '1' , '1' , 26)

这为数据长度为26的数据包构建了一个标头,但是当解包数据时,我不确定如何在之后获取其余数据。要打开包装,我们需要知道所有字段的大小,除非我遗漏了什么?我想打包数据我会使用格式指示符'cch26s'的含义:

1 Byte char
1 Byte char
2 Byte short
26 Byte char array

但是,当我不知道数据包中将包含多少数据时,如何解压缩数据呢?

2 个答案:

答案 0 :(得分:3)

您描述协议的方式,您应首先解包前四个字节,然后提取长度(16位int)。这告诉你在第二步中要解包的字节数。

version, type, length = struct.unpack("cch", packed[:4])
content, = struct.unpack("%ds" % length, packed[4:])

如果一切都结束了。 unpack()要求打包缓冲区包含与解压缩数据完全相同的数据。另外,检查长度计数中是否包含4个头字节。

答案 1 :(得分:2)

您可以通过检查len(data)来猜测要解包的字符数。

这是一个帮助你的函数:

def unpack(fmt, astr):
    """
    Return struct.unpack(fmt, astr) with the optional single * in fmt replaced with
    the appropriate number, given the length of astr.
    """
    # http://stackoverflow.com/a/7867892/190597
    try:
        return struct.unpack(fmt, astr)
    except struct.error:
        flen = struct.calcsize(fmt.replace('*', ''))
        alen = len(astr)
        idx = fmt.find('*')
        before_char = fmt[idx-1]
        n = (alen-flen)/struct.calcsize(before_char)+1
        fmt = ''.join((fmt[:idx-1], str(n), before_char, fmt[idx+1:]))
        return struct.unpack(fmt, astr)

你可以像这样使用它:

unpack('cchs*', data)