您的位置:首页 > 编程语言 > C语言/C++

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

2017-06-12 20:34 776 查看
本文参考: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”

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python socket c语言