在 python ctypes 中访问和复制 C 结构体数组

问题描述 投票:0回答:1

我有一个嵌套的C++结构,我试图使用UDP发送到python并获取那里的值。

#define _WINSOCK_DEPRECATED_NO_WARNINGS

#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "Ws2_32.lib")

#include <iostream>
#include <winsock2.h>



struct MyStruct {
    int intValue;
    float floatValue;
    // Add more members as needed

    struct MyInnerStruct {
        int intValue;
        float floatValue;
    };

    MyInnerStruct *InnerStruct;
};



int main() {

    MyStruct testStruct;
    testStruct.floatValue = 3.1;
    testStruct.intValue = 4;
    testStruct.InnerStruct = new MyStruct::MyInnerStruct[4];

    for (int i = 0; i < 4; i++) {
        testStruct.InnerStruct[i].intValue = i + 23;
        testStruct.InnerStruct[i].floatValue = (i/10) + 23;
    
    }





    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cerr << "Failed to initialize winsock." << std::endl;
        return 1;
    }

    char hostname[256];
    char ip[100];

    // Get the hostname
    if (gethostname(hostname, sizeof(hostname)) == 0) {
        std::cout << "Hostname: " << hostname << std::endl;

        // Get the IP address
        struct hostent* host_info = gethostbyname(hostname);
        if (host_info != nullptr) {
            struct in_addr* address = reinterpret_cast<struct in_addr*>(host_info->h_addr);
            strcpy(ip, inet_ntoa(*address));
            std::cout << "IP Address: " << ip << std::endl;
        }
        else {
            std::cerr << "Error getting host information." << std::endl;
        }
    }
    else {
        std::cerr << "Error getting hostname." << std::endl;
    }
    int udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if (udpSocket == -1) {
        perror("Error creating socket");
        exit(EXIT_FAILURE);
    }

    // Server address
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(12345); // Choose a port
    serverAddr.sin_addr.s_addr = inet_addr(ip); // Replace with the server's IP

    

    // Serialize the struct into a byte stream
    char buffer[sizeof(MyStruct)];
    memcpy(buffer, &testStruct, sizeof(MyStruct));

    // Send the serialized struct over the UDP socket
    if (sendto(udpSocket, buffer, sizeof(MyStruct), 0, reinterpret_cast<sockaddr*>(&serverAddr), sizeof(serverAddr)) == -1) {
        perror("Error sending data");
        closesocket(udpSocket);
        exit(EXIT_FAILURE);
    }

    std::cout << "Struct sent successfully." << std::endl;

    // Clean up
    closesocket(udpSocket);

    
    WSACleanup();
    return 0;
}

但是在 python 中我似乎无法获取嵌套的 c++ 结构的值

import socket
import struct
from ctypes import *
# IP address and port number for server
HOST = '127.0.0.1'
PORT = 12345

class MyInnerStruct(Structure):
    _fields_ = [
        ('field4', c_int),
        ('field5', c_float),
        
    ] 

class MyStruct(Structure):
    _fields_ = [
        ('field1', c_int),
        ('field2', c_float),
        ('field3', POINTER(MyInnerStruct)),
    ]


sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((HOST, PORT))

while True:
   
    data, addr = sock.recvfrom(sizeof(MyStruct))
    
    received_struct = cast(data, POINTER(MyStruct)).contents

  
  
   # Access the fields of the received struct
    field1 = received_struct.field1
    field2 = received_struct.field2
    field3 = received_struct.field3

    received_inner_struct = cast(field3, POINTER(MyInnerStruct)).contents

   

    for i in range(field1):
        array[i].field4 = field3[i].field4
        array[i].field5 = field3[i].field5   //these lines are not working
    

    

    

# Close the socket
sock.close()

我尝试通过尝试取消引用来访问内部嵌套结构(在for循环中)的值,但我不能,我如何访问内部结构中的字段4和字段5

python c++ sockets ctypes
1个回答
0
投票

在 C 中,为每个数组元素发送等效的 field1-3,然后发送 field4-5。这是我用于测试的 Python 等效项:

import struct
import socket

# send field1=4, field2, and 4x the two fields of each array element.
data = struct.pack('<ififififif', 4, 3.5, 1, 1.25, 2, 2.5, 3, 2.75, 4, 3.00)

with socket.socket(type=socket.SOCK_DGRAM) as s:
    s.sendto(data, ('localhost', 5000))

一种解压方式,但效率不过分。要接收,请读取前两个字段并初始化

MyStruct
的字段 1-2。使用
field1
分配
MyInnerStruct
数组。然后从缓冲区中读取 field4-5 对并初始化数组。最后,将数组分配给
MyStruct.field3

import socket
import struct
import ctypes as ct

class MyInnerStruct(ct.Structure):
    _fields_ = (('field4', ct.c_int),
                ('field5', ct.c_float))
    def __repr__(self):  # for display
        return f'({self.field4}, {self.field5})'

class MyStruct(ct.Structure):
    _fields_ = (('field1', ct.c_int),
                ('field2', ct.c_float),
                ('field3', ct.POINTER(MyInnerStruct)))
    def __repr__(self):  # for display
        return f'[{self.field1}, {self.field2}, {list(self.field3[:self.field1])})]'

sock = socket.socket(type=socket.SOCK_DGRAM)
sock.bind(('', 5000))

data, addr = sock.recvfrom(40960)
field1, field2 = struct.unpack_from('<if', data)
received_struct = MyStruct(field1, field2)  # pointer is null at this point

inner_array = (MyInnerStruct * field1)()  # allocate inner array
start_of_inner = struct.calcsize('if')  # index data after MyStruct fields
size_of_inner = struct.calcsize('if')   # size of inner array element
index = start_of_inner
for i in range(field1):
    field4, field5 = struct.unpack_from('<if', data[index:])  # read fields of an array element
    inner_array[i] = MyInnerStruct(field4, field5) # assign to the array element
    index += size_of_inner
received_struct.field3 = inner_array  # pointer to the initialized inner array
print(received_struct)  # now print complete received item.

运行接收者代码等待数据包,然后运行发送者代码发送数据包:

接收器输出:

[4, 3.5, [(1, 1.25), (2, 2.5), (3, 2.75), (4, 3.0)])]
© www.soinside.com 2019 - 2024. All rights reserved.