Python UDP Socket传输GPS数据时struct.unpack报错求助
问题描述
使用Python Socket实现GPS数据UDP传输,发送端运行正常,接收端启动后触发错误:
struct.error: unpack requires a buffer of 24 bytes
发送端代码
import socket import struct import time RECEIVER_IP = "localhost" RECEIVER_PORT = 17781 class gps_packet: def __init__(self, latitude, latitude_indicator, longitude, longitude_indicator, dilution_of_precision, horizontal_dilution_of_precision, vertical_dilution_of_precision): self.latitude = latitude self.latitude_indicator = 1 if latitude_indicator == 'N' else -1 self.longitude = longitude self.longitude_indicator = 1 if longitude_indicator == 'E' else -1 self.dilution_of_precision = dilution_of_precision self.horizontal_dilution_of_precision = horizontal_dilution_of_precision self.vertical_dilution_of_precision = vertical_dilution_of_precision def create_udp_socket(): try: sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return sockfd except socket.error as e: print("Failed to create sender socket:", e) return None def send_gps_data(sockfd, gps_data): try: payload = struct.pack('dbdbddd', gps_data.latitude, gps_data.latitude_indicator, gps_data.longitude, gps_data.longitude_indicator,gps_data.dilution_of_precision, gps_data.horizontal_dilution_of_precision, gps_data.vertical_dilution_of_precision) base_packet = struct.pack('IILQ', 277, 10220, 0, 0) # Message ID, Message Length, Base Packet message = base_packet + payload sockfd.sendto(message, (RECEIVER_IP, RECEIVER_PORT)) print("GPS data sent successfully") except socket.error as e: print("Failed to send GPS data:", e) def main(): sockfd = create_udp_socket() if not sockfd: return # Example GPS data gps_data = gps_packet(latitude=37.7749, latitude_indicator='N', longitude=-122.4194, longitude_indicator='W', dilution_of_precision=1.2, horizontal_dilution_of_precision=1.5, vertical_dilution_of_precision=1.8) while True: send_gps_data(sockfd, gps_data) time.sleep(1) # Send data every 1 second if __name__ == "__main__": main()
接收端代码
import socket import struct RECEIVER_PORT = 17781 BASE_PACKET_PAYLOAD_SIZE = 10096 class BasePacket: def __init__(self, crc32, count, version, timestamp, payload): self.crc32 = crc32 self.count = count self.version = version self.timestamp = timestamp self.payload = payload class PDUMessage: def __init__(self, messageID, messageLength, basePacket): self.messageID = messageID self.messageLength = messageLength self.basePacket = basePacket class gps_packet: def __init__(self, latitude, latitude_indicator, longitude, longitude_indicator, dilution_of_precision, horizontal_dilution_of_precision, vertical_dilution_of_precision): self.latitude = latitude self.latitude_indicator = latitude_indicator self.longitude = longitude self.longitude_indicator = longitude_indicator self.dilution_of_precision = dilution_of_precision self.horizontal_dilution_of_precision = horizontal_dilution_of_precision self.vertical_dilution_of_precision = vertical_dilution_of_precision def create_udp_socket(): try: sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print("Receiver socket opened") return sockfd except socket.error as e: print("Failed to create receiver socket:", e) return None def bind_socket(sockfd, port): try: sockfd.bind(("", port)) print("Socket bound successfully") return True except socket.error as e: print("Failed to bind socket:", e) return False def receive_data(sockfd): try: data, sender_addr = sockfd.recvfrom(4096) # Ensure the received data is at least 24 bytes before unpacking if len(data) < 24: print("Received data too short:", len(data), "bytes") return None, None received_message = struct.unpack('IILQ', data[:20]) # Unpack the fixed part of the message payload = struct.unpack('10096s', data[20:])[0] # Unpack the payload received_message = PDUMessage(received_message[0], received_message[1], BasePacket(received_message[2], received_message[3], received_message[4], received_message[5], payload)) return received_message, sender_addr except socket.error as e: print("Failed to receive data:", e) return None, None def get_gps_data(sockfd): while True: print("data thread") received_message, sender_addr = receive_data(sockfd) if received_message.messageID == 277: recv_packet = gps_packet(*struct.unpack('dbdbddd', received_message.basePacket.payload)) print("Received data from IP:", sender_addr[0]) print(recv_packet.horizontal_dilution_of_precision) print("data received successfully") def main(): sockfd = create_udp_socket() if not sockfd: return if not bind_socket(sockfd, RECEIVER_PORT): sockfd.close() return get_gps_data(sockfd) if __name__ == "__main__": main()
错误栈信息
Receiver socket opened Socket bound successfully data thread Traceback (most recent call last): File "/home/jangoo/Map_Optimize/./reciever_socket_2.py", line 103, in <module> main() File "/home/jangoo/Map_Optimize/./reciever_socket_2.py", line 99, in main get_gps_data(sockfd) File "/home/jangoo/Map_Optimize/./reciever_socket_2.py", line 79, in get_gps_data received_message, sender_addr = receive_data(sockfd) File "/home/jangoo/Map_Optimize/./reciever_socket_2.py", line 65, in receive_data received_message = struct.unpack('IILQ', data[:20]) # Unpack the fixed part of the message struct.error: unpack requires a buffer of 24 bytes
解决方案
问题根源
- 结构体字节数不匹配:发送端用
IILQ格式打包头部,在64位系统中该格式总字节数为24(4+4+8+8),但接收端硬编码取前20字节解析,导致字节长度不足。 - 数据包结构定义不一致:发送端头部仅包含4个字段,接收端却错误映射为6个字段的
BasePacket结构,逻辑完全不匹配。 - Payload长度错误:发送端实际Payload为40字节(
dbdbddd格式),接收端却按10096字节解析,长度严重不符。
修正后的接收端代码
import socket import struct RECEIVER_PORT = 17781 class PDUMessage: def __init__(self, messageID, messageLength, reserved1, reserved2, payload): self.messageID = messageID self.messageLength = messageLength self.reserved1 = reserved1 self.reserved2 = reserved2 self.payload = payload class gps_packet: def __init__(self, latitude, latitude_indicator, longitude, longitude_indicator, dilution_of_precision, horizontal_dilution_of_precision, vertical_dilution_of_precision): self.latitude = latitude self.latitude_indicator = latitude_indicator self.longitude = longitude self.longitude_indicator = longitude_indicator self.dilution_of_precision = dilution_of_precision self.horizontal_dilution_of_precision = horizontal_dilution_of_precision self.vertical_dilution_of_precision = vertical_dilution_of_precision def create_udp_socket(): try: sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print("Receiver socket opened") return sockfd except socket.error as e: print("Failed to create receiver socket:", e) return None def bind_socket(sockfd, port): try: sockfd.bind(("", port)) print("Socket bound successfully") return True except socket.error as e: print("Failed to bind socket:", e) return False def receive_data(sockfd): try: data, sender_addr = sockfd.recvfrom(4096) # 动态计算头部长度,避免硬编码适配不同系统 header_size = struct.calcsize('IILQ') if len(data) < header_size: print(f"Received data too short: {len(data)} bytes, need at least {header_size} bytes") return None, None # 解析头部字段,和发送端结构保持一致 header_fields = struct.unpack('IILQ', data[:header_size]) messageID, messageLength, reserved1, reserved2 = header_fields # 提取实际Payload数据 payload = data[header_size:] # 验证Payload长度是否匹配预期格式 expected_payload_size = struct.calcsize('dbdbddd') if len(payload) != expected_payload_size: print(f"Payload size mismatch: received {len(payload)} bytes, expected {expected_payload_size}") return None, None received_message = PDUMessage(messageID, messageLength, reserved1, reserved2, payload) return received_message, sender_addr except Exception as e: print("Failed to receive data:", e) return None, None def get_gps_data(sockfd): while True: print("Waiting for data...") received_message, sender_addr = receive_data(sockfd) if not received_message: continue if received_message.messageID == 277: try: # 解析GPS数据并转换指示器为方向字符 gps_fields = struct.unpack('dbdbddd', received_message.payload) recv_packet = gps_packet(*gps_fields) recv_packet.latitude_indicator = 'N' if recv_packet.latitude_indicator == 1 else 'S' recv_packet.longitude_indicator = 'E' if recv_packet.longitude_indicator == 1 else 'W' print("Received data from IP:", sender_addr[0]) print(f"Latitude: {recv_packet.latitude} {recv_packet.latitude_indicator}") print(f"Longitude: {recv_packet.longitude} {recv_packet.longitude_indicator}") print(f"Horizontal Dilution: {recv_packet.horizontal_dilution_of_precision}") print("Data received successfully") except Exception as e: print("Failed to parse GPS data:", e) def main(): sockfd = create_udp_socket() if not sockfd: return if not bind_socket(sockfd, RECEIVER_PORT): sockfd.close() return get_gps_data(sockfd) if __name__ == "__main__": main()
发送端可选优化(修正MessageLength字段)
将发送端的messageLength改为实际Payload长度,保证字段语义正确:
def send_gps_data(sockfd, gps_data): try: payload = struct.pack('dbdbddd', gps_data.latitude, gps_data.latitude_indicator, gps_data.longitude, gps_data.longitude_indicator,gps_data.dilution_of_precision, gps_data.horizontal_dilution_of_precision, gps_data.vertical_dilution_of_precision) # 使用实际Payload长度替换硬编码值 payload_length = len(payload) base_packet = struct.pack('IILQ', 277, payload_length, 0, 0) message = base_packet + payload sockfd.sendto(message, (RECEIVER_IP, RECEIVER_PORT)) print("GPS data sent successfully") except socket.error as e: print("Failed to send GPS data:", e)
内容的提问来源于stack exchange,提问作者user23369001
相关产品推荐
相关产品推荐

