Python TCP Socket接收C++结构体数据并解析展示的示例请求
问题分析
原C++代码的核心问题是直接memcpy包含std::string的结构体完全不可行:std::string内部存储的是指向堆内存的指针,sizeof(student)仅计算了指针、int数组、float的固定大小,并没有包含字符串的实际内容。发送后Python端拿到的只是无效的指针地址,根本无法还原真实字符串。
正确的C++序列化与发送实现
需要手动将结构体序列化为可传输的字节流,按固定格式依次发送每个字段的内容,示例代码如下:
#include <vector> #include <cstring> #include <arpa/inet.h> // 用于字节序转换 typedef struct { int enable; std::string name; int numbers[5]; float counter; } Student; // 序列化Student结构体为字节流 std::vector<uint8_t> serializeStudent(const Student& student) { std::vector<uint8_t> data; // 序列化enable:转换为网络字节序(大端) uint32_t enable_be = htonl(student.enable); data.insert(data.end(), reinterpret_cast<uint8_t*>(&enable_be), reinterpret_cast<uint8_t*>(&enable_be) + sizeof(enable_be)); // 序列化name:先发送字符串长度(网络字节序),再发送字符串内容 uint32_t name_len_be = htonl(student.name.size()); data.insert(data.end(), reinterpret_cast<uint8_t*>(&name_len_be), reinterpret_cast<uint8_t*>(&name_len_be) + sizeof(name_len_be)); data.insert(data.end(), student.name.begin(), student.name.end()); // 序列化numbers数组:每个int转换为网络字节序 for (int num : student.numbers) { uint32_t num_be = htonl(num); data.insert(data.end(), reinterpret_cast<uint8_t*>(&num_be), reinterpret_cast<uint8_t*>(&num_be) + sizeof(num_be)); } // 序列化counter:先转为uint32_t再处理字节序 uint32_t counter_raw; std::memcpy(&counter_raw, &student.counter, sizeof(counter_raw)); uint32_t counter_be = htonl(counter_raw); data.insert(data.end(), reinterpret_cast<uint8_t*>(&counter_be), reinterpret_cast<uint8_t*>(&counter_be) + sizeof(counter_be)); return data; } // TCP发送函数示例 void sendDataOverTCPSocket(const std::vector<uint8_t>& data, int sockfd) { send(sockfd, data.data(), data.size(), 0); } // 使用示例 // Student s{1, "Alice", {10,20,30,40,50}, 3.14f}; // auto serialized_data = serializeStudent(s); // sendDataOverTCPSocket(serialized_data, your_socket_fd);
Python服务器端解析实现
基于基础TCP服务器框架,按C++的序列化格式反向解析数据:
import socket import struct def parse_student(raw_data): offset = 0 # 解析enable:网络字节序转主机字节序 enable = struct.unpack('!I', raw_data[offset:offset+4])[0] offset += 4 # 解析name的长度与内容 name_len = struct.unpack('!I', raw_data[offset:offset+4])[0] offset +=4 name = raw_data[offset:offset+name_len].decode('utf-8') offset += name_len # 解析numbers数组 numbers = [] for _ in range(5): num = struct.unpack('!I', raw_data[offset:offset+4])[0] numbers.append(num) offset +=4 # 解析counter:先还原uint32_t再转float counter_raw = struct.unpack('!I', raw_data[offset:offset+4])[0] counter = struct.unpack('f', struct.pack('I', counter_raw))[0] offset +=4 return { 'enable': enable, 'name': name, 'numbers': numbers, 'counter': counter } def main(): host = '0.0.0.0' port = 12345 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((host, port)) server_socket.listen(5) print(f"Server listening on {host}:{port}") while True: client_socket, addr = server_socket.accept() print(f"Connected to {addr}") # 接收数据:生产环境需处理粘包,可先接收总长度再接收对应字节数 raw_data = client_socket.recv(1024) if not raw_data: client_socket.close() continue student_info = parse_student(raw_data) print("\nReceived Student Data:") print(f"Enable: {student_info['enable']}") print(f"Name: {student_info['name']}") print(f"Numbers: {student_info['numbers']}") print(f"Counter: {student_info['counter']:.2f}") client_socket.close() if __name__ == "__main__": main()
关键注意事项
- 字节序一致性:C++用
htonl转换为网络字节序(大端),Python用!格式符对应网络字节序,避免跨平台解析错误 - 粘包处理:实际生产环境中,需先发送序列化数据的总长度,Python端先接收长度再读取对应字节数的内容,防止粘包
- 字符串编码:示例使用UTF-8编码,C++和Python需保持编码一致
- float解析:通过先转换为uint32_t处理字节序,再转回float,保证浮点值解析正确
内容的提问来源于stack exchange,提问作者jkafernando
相关产品推荐
相关产品推荐

