I've followed C-like structures in Python, and i defined a class CommandHeader
that inherits ctypes.Structure
.
class CommandHeader(Structure):
"""
struct {
uint8_t key;
uint8_t flag;
uint16_t command;
uint16_t length;
uint16_t req_id;
}
"""
_fields_ = [
('key', c_uint8),
('flag', c_uint8),
('command', c_uint16),
('length', c_uint16),
('req_id', c_uint16),
]
But i have another requirement that is convert this C-like structure into bytes.
So i have to use struct
module and define two member function that is pack
and unpack
.
class CommandHeader(Structure):
"""
struct {
uint8_t key;
uint8_t flag;
uint16_t command;
uint16_t length;
uint16_t req_id;
}
"""
_fields_ = [
('key', c_uint8),
('flag', c_uint8),
('command', c_uint16),
('length', c_uint16),
('req_id', c_uint16),
]
def pack(self):
return struct.pack('!BBHHH', self.key, self.flag, self.command, self.length, self.req_id)
def unpack(self, data):
self.key, self.flag, self.command, self.length, self.req_id = struct.unpack('!BBHHH', data)
This code can work normally.
But i think pack
and unpack
member function is not well, because i have to define this two member function for every class that like CommandHeader
.
In addition, if a class has a lot of members, then the pack
and unpack
member function will be very long, which looks very ugly.
class DIS_ACK(Structure):
ack_fmt = '!HHIHHIIIIIIIIIIIIIII32s32s32s48s16s16s'
ack_size = 248
_fields_ = [
('header', ACK_HEADER),
('spec_version_major', c_ushort),
('spec_version_minor', c_ushort),
('device_mode', c_uint),
('reserved_0', c_ushort),
('device_mac_address_high', c_ushort),
('device_mac_address_low', c_uint),
('ip_config_options', c_uint),
('ip_config_current', c_uint),
('reserved_1', c_uint),
('reserved_2', c_uint),
('reserved_3', c_uint),
('current_ip', c_uint),
('reserved_4', c_uint),
('reserved_5', c_uint),
('reserved_6', c_uint),
('current_subnet_mask', c_uint),
('reserved_7', c_uint),
('reserved_8', c_uint),
('reserved_9', c_uint),
('default_gateway', c_uint),
('manufacturer_name', c_char_p), # 32
('model_name', c_char_p), # 32
('device_version', c_char_p), # 32
('manufacturer_spec_info', c_char_p), # 48
('serial_number', c_char_p), # 16
('user_defined_name', c_char_p) # 16
]
def unpack(self, sock_data):
self.header.unpack(sock_data)
if self.header.length == self.ack_size:
(self.spec_version_major,
self.spec_version_minor,
self.device_mode,
self.reserved_0,
self.device_mac_address_high,
self.device_mac_address_low,
self.ip_config_options,
self.ip_config_current,
self.reserved_1,
self.reserved_2,
self.reserved_3,
self.current_ip,
self.reserved_4,
self.reserved_5,
self.reserved_6,
self.current_subnet_mask,
self.reserved_7,
self.reserved_8,
self.reserved_9,
self.default_gateway,
self.manufacturer_name,
self.model_name,
self.device_version,
self.manufacturer_spec_info,
self.serial_number,
self.user_defined_name) = struct.unpack(self.ack_fmt,
sock_data[self.header.header_size:])
def pack(self):
self.header.command = 0x0003
if self.header.length != self.ack_size:
return self.header.pack()
return self.header.pack() + struct.pack(self.ack_fmt,
self.spec_version_major,
self.spec_version_minor,
self.device_mode,
self.reserved_0,
self.device_mac_address_high,
self.device_mac_address_low,
self.ip_config_options,
self.ip_config_current,
self.reserved_1,
self.reserved_2,
self.reserved_3,
self.current_ip,
self.reserved_4,
self.reserved_5,
self.reserved_6,
self.current_subnet_mask,
self.reserved_7,
self.reserved_8,
self.reserved_9,
self.default_gateway,
self.manufacturer_name,
self.model_name,
self.device_version,
self.manufacturer_spec_info,
self.serial_number,
self.user_defined_name
So is there some better way to do this?