You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

解决方案

问题根源

  1. 结构体字节数不匹配:发送端用IILQ格式打包头部,在64位系统中该格式总字节数为24(4+4+8+8),但接收端硬编码取前20字节解析,导致字节长度不足。
  2. 数据包结构定义不一致:发送端头部仅包含4个字段,接收端却错误映射为6个字段的BasePacket结构,逻辑完全不匹配。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 23:32:32