Python uses the struct module to convert C language structures, pack and unpack binary data

Reference for this article: https://docs.python.org/2/library/struct.html#struct-format-strings

This article is the message header I wrote using the socket test network interface, which contains the following contents:
(1) Convert the C structure into Python language (struct.Struct) through Python's struct module
(2) Packing and unpacking (pack_into and unpack_from )
(3) Serialization and deserialization (SerializeToString and ParseFromString)

The message header of the C language is as follows, which is a C structure:

#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()

Convert the message header of the C language into a Python class, where reserve[1] is a reserved word, don't care, body[0] is an array of length 0, save the first address of the body, don't care. After conversion as follows

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]

Byte order:
1. The first character of the byte order can be used to indicate the byte order, size and way of the packed datawrite picture description here


2. Type conversion between format characters C and Python, the combined string represents the byte order of binary data, such as "!IHIcc" in the above program
write picture description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324459240&siteId=291194637