Python使用struct模块转换C语言结构体,打包、解包二进制数据

原创 2017年06月12日 20:34:06

本文参考:https://docs.python.org/2/library/struct.html#struct-format-strings

本文是我使用socket测试网络接口写的消息头,其中包含以下内容:
(1)通过Python的struct模块将C的结构体转换成Python语言(struct.Struct)
(2)打包和解包(pack_into和unpack_from)
(3)序列化和反序列化(SerializeToString和ParseFromString)

C语言的消息头如下,是个C的结构体:

#pragma pack(1)
struct PduHead{
         unsigned int   flag; 
         unsigned short packet_len;
         unsigned int   cmd;
         unsigned char  version;
         unsigned char  reserve[1];
         unsigned char  body[0];
};
#pragma pack()

将C语言的消息头转换为Python类,其中reserve[1]是保留字,不用管,body[0]是个长度为0的数组,保存body的首地址,也不用管。转换后如下

import struct
import ctypes

class PduHead(object):
    def __init__(self, cmdtype=0):
        self.flag = GLOBAL_SIGNAL_FLAG
        self.packet_len = 0
        self.cmd = cmdtype
        self.version = VERSION
        # struct.Struct返回一个新的Struct对象,根据传入的字节顺序字符串写入和读取二进制数据
        # “!IHIcc”表示二进制数据的字节顺序
        # “!”表示字节顺序为network
        # “IHIcc”分别是根据以上几个参数的类型得到的格式字符
        # 二进制流会根据这个字节顺序去解析          
        self.struct = struct.Struct('!IHIcc')

    # 序列化函数
    def SerializeToStringWithMsg(self, req_msg):
        if not req_msg:
            logger.error('No request message set!')
            return ''
        body_str = req_msg.SerializeToString()  # 序列化,将对象转化为可传输的二进制流
        values = (self.flag, len(body_str) + self.struct.size, self.cmd, self.version, '\0')
        buffer = ctypes.create_string_buffer(self.struct.size) # 创建一个buffer
        self.struct.pack_into(buffer, 0, *values)  # 根据字节序打包,将打包的字节写入到buffer中,values元组表示要写入的值
        # buffer对象提供了raw属性访问当前buffer内容
        # 该方法返回一个要传输的消息头和消息体的二进制流
        return buffer.raw + body_str 

    # 反序列化函数
    def ParseFromStringWithMsg(self, data):
        # 根据字节序解析二进制流,返回一个元素,形似SerializeToStringWithMsg方法中的value,所以self.cmd是元组的第三个元素
        self.cmd = self.struct.unpack_from(data[:self.struct.size])[2]  
        resp_msg = dict_message.get(self.cmd)  # 根据self.cmd得到响应数据的二进制流(这是个不用关心,跟业务有关)
        if not resp_msg:
            logger.error('Message [%d] Not Found!' % self.cmd)
            return None
        resp_msg = resp_msg()
        if resp_msg:
            resp_msg.ParseFromString(data[self.struct.size:])  # 反序列化,将二进制流转化为实际的对象
        return [self.cmd, resp_msg]

字节顺序:
1、字节顺序的第一个字符可用于指示打包数据的字节顺序、大小和对其方式这里写图片描述

2、格式字符
C和Python之间的类型转换,组合的字符串表示二进制数据的字节顺序,如上面程序中的“!IHIcc”
这里写图片描述

7 Python struct模块-深入学习

深入学习Python中struct模块,大小端,pack()、unpack()函数
  • lis_12
  • lis_12
  • 2016年10月10日 15:11
  • 4331

Python struct模块-深入学习

Python struct模块 Python struct模块 用处struct模块中的函数格式化字符串 对齐方式格式符 code使用示例Python参考手册struct模块链接 ...
  • shuyun123456789
  • shuyun123456789
  • 2017年09月29日 13:52
  • 437

Python模块学习 ---- struct处理二进制

有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c语言中的结构体....
  • dong50252409
  • dong50252409
  • 2014年09月15日 15:29
  • 1039

Python之struct模块(处理二进制)

有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c语言中的结构体. struct模块中...
  • B_H_L
  • B_H_L
  • 2013年07月18日 18:05
  • 1104

Python学习——struct模块的pack、unpack示例

Python学习——struct模块的pack、unpack示例 标签: pythonstructstringintegercharacter 2010-10-29 13:36 45327...
  • linuxheik
  • linuxheik
  • 2016年07月11日 18:07
  • 4227

python struct 详解

python struct  from http://blog.csdn.net/jgood/article/details/4290158  struct.pack   struct.pack...
  • occupy8
  • occupy8
  • 2013年09月04日 13:54
  • 9238

Python模块——struct(字节流,组包拆包实现)

我们知道python只定义了6种数据类型,字符串,整数,浮点数,列表,元组,字典。但是C语言中有些字节型的变量,在python中该如何实现呢?这点颇为重要,特别是要在网络上进行数据传输的话。    ...
  • tycoon1988
  • tycoon1988
  • 2014年08月22日 18:06
  • 1466

Python学习——struct模块的pack、unpack示例

Python是一门非常简洁的语言,对于数据类型的表示,不像其他语言预定义了许多类型(如:在C#中,光整型就定义了8种),它只定义了六种基本类型:字符串,整数,浮点数,元组,列表,字典。通过这六种数据类...
  • sunboy_2050
  • sunboy_2050
  • 2010年10月29日 13:36
  • 87169

Torch7入门续集(三)----Simple Layers的妙用

我已经不太想写Torch的博客了~~没劲。
  • Hungryof
  • Hungryof
  • 2017年03月13日 13:45
  • 2677

python模块详解

  • 2012年02月29日 21:06
  • 110KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Python使用struct模块转换C语言结构体,打包、解包二进制数据
举报原因:
原因补充:

(最多只允许输入30个字)