我有一个连接到嵌入式服务器的python客户端,我们使用c结构进行通信,能够将结构发送到服务器,并且他能够接收和解析我的结构,套接字响应还是我所构造的结构无法解析,结构格式没有变化。
from ctypes import *
class CommonMessage(Structure):
_pack_ = 1
_fields_ = [
("sof", c_uint), ("request_id", c_uint),
("interface", c_uint), ("msg_type", c_uint),
("response", c_uint),
("data_len", c_int),
("data", c_ubyte * msg_length)
]
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('192.168.98.64', 7000)
sock.connect(server_address)
sock.sendall(message_proto)
sz = sizeof(message_proto)
data = sock.recv(sz)
print(data)
b'\xcc\xdd\xee\xff~Y\xd4\x0b\x02\xb9\xa9\x00i\x02\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00'
parsed_data = CommonMessage.from_buffer_copy(data)
尝试解析结构数据时出错
缓冲区大小太小(24个字节,而不是至少93个字节)
请帮忙。...
答案 0 :(得分:1)
从 ctypes 文档页面开始:[Python]: ctypes - A foreign function library for Python。
这里有一个设计问题。想象一下以下情形:另一部分发送标头+数据(两次),如:
data_len
= 15),以及与 struct data_len
= 25),以及与 struct 您不能使用静态 定义的CommonMessage
对该场景进行建模。您需要做的是,将其分为2个部分( header 和 data ),每次您想获取一条消息时,
data_len
的标题data_len
个字节这是常规解决方案,适用于所有此类情况。如果您的情况存在特殊性,则可以使用其他方法-要么更简单(从代码 PoV 中提取),要么更快-但这些方法仅适用于那些特殊性。但是,由于该问题未提及任何此类特殊性(甚至不是 mcve -
由于代码无法编译 OOTB ),因此我将坚持使用通用解决方案。
请注意,它与[SO]: multiple send from server to client python
(@CristiFati's answer)相同。
code.py :
import sys
import ctypes
# b"\xcc\xdd\xee\xff~Y\xd4\x0b\x02\xb9\xa9\x00i\x02\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" # Original buffer
INPUT_BUFFER = b"\xcc\xdd\xee\xff~Y\xd4\x0b\x02\xb9\xa9\x00i\x02\x00\x00\x01\x00\x00\x00\x0F\x00\x00\x00\x01\x02\x03\x04\x05Dummy TextIGNORED PART" # At the end, there are bytes for data
# ^ - Modified data length to 15
class CommonMessageHeader(ctypes.Structure):
_pack_ = 1
_fields_ = [
("sof", ctypes.c_uint),
("request_id", ctypes.c_uint),
("interface", ctypes.c_uint),
("msg_type", ctypes.c_uint),
("response", ctypes.c_uint),
("data_len", ctypes.c_int),
]
def print_ctypes_instance_info(obj, indent="", metadata="", max_array_items=10, indent_increment=" "):
if metadata:
print("{:s}{:s}: {:}".format(indent, metadata, obj))
else:
print("{:s}[{:}]: {:}".format(indent, type(obj), obj))
if isinstance(obj, ctypes.Structure):
for field_name, field_type in obj._fields_:
print_ctypes_instance_info(getattr(obj, field_name),indent=indent + indent_increment, metadata="[{:}] {:s}".format(field_type, field_name))
elif isinstance(obj, ctypes.Array):
if max_array_items < len(obj):
items_len, extra_line = max_array_items, True
else:
items_len, extra_line = len(obj), False
for idx in range(items_len):
print_ctypes_instance_info(obj[idx], indent=indent + indent_increment, metadata="[{:d}]".format(idx))
if extra_line:
print("{:s}...".format(indent + indent_increment))
def get_instance_from_buffer(buffer):
header_len = ctypes.sizeof(CommonMessageHeader)
if header_len > len(buffer):
raise ValueError(-1, "Buffer smaller than header")
header = CommonMessageHeader.from_buffer_copy(buffer)
required_buf_len = header_len + header.data_len
if required_buf_len > len(buffer):
raise ValueError(-2, "Buffer smaller than header and data")
class CommonMessage(ctypes.Structure):
_pack_ = 1
_fields_ = [
("header", CommonMessageHeader),
("data", ctypes.c_ubyte * header.data_len)
]
return CommonMessage.from_buffer_copy(buffer), required_buf_len
def main():
print("sizeof(CommonMessageHeader): {:d}".format(ctypes.sizeof(CommonMessageHeader)))
print("Input buffer len: {:d}\n".format(len(INPUT_BUFFER)))
inst, inst_len = get_instance_from_buffer(INPUT_BUFFER)
print_ctypes_instance_info(inst)
print("\nOutput data as a string ({:d}): [{:s}]".format(len(inst.data), "".join([repr(chr(item))[1:-1] for item in inst.data])))
print("The rest of the buffer: [{:}]".format(INPUT_BUFFER[inst_len:]))
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
注释:
print_ctypes_instance_info
)仅用于打印对象get_instance_from_buffer
是试图将现有缓冲区转换为CommonMessage
(与现在的问题CommonMessageHeader
中的那个不同)的函数:
CommonMessage
类(例如,它不像CommonMessageHeader
那样全局),因为ctypes.Structure._fields_
只能设置一次 < / li>
ValueError
输出:
(py35x64_test) e:\Work\Dev\StackOverflow\q051086829>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32 sizeof(CommonMessageHeader): 24 Input buffer len: 51 [<class '__main__.get_instance_from_buffer.<locals>.CommonMessage'>]: <__main__.get_instance_from_buffer.<locals>.CommonMessage object at 0x000002106F1BBBC8> [<class '__main__.CommonMessageHeader'>] header: <__main__.CommonMessageHeader object at 0x000002106F1BBB48> [<class 'ctypes.c_ulong'>] sof: 4293844428 [<class 'ctypes.c_ulong'>] request_id: 198465918 [<class 'ctypes.c_ulong'>] interface: 11122946 [<class 'ctypes.c_ulong'>] msg_type: 617 [<class 'ctypes.c_ulong'>] response: 1 [<class 'ctypes.c_long'>] data_len: 15 [<class '__main__.c_ubyte_Array_15'>] data: <__main__.c_ubyte_Array_15 object at 0x000002106F1BBB48> [0]: 1 [1]: 2 [2]: 3 [3]: 4 [4]: 5 [5]: 68 [6]: 117 [7]: 109 [8]: 109 [9]: 121 ... Output data as a string (15): [\x01\x02\x03\x04\x05Dummy Text] The rest of the buffer: [b'IGNORED PART']