Hwy, I am working on socket in python and try to send data from between 2 application through sockets
Here is the sender code :
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
# print(message)
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()
And below is receiver code :
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)
# print(received_message)
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()
Now when I start the sender code it working fine but at the receiver code the terminal shows below error and related error
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
Now I am stuck at it, I want to have the data transfer between 2 applications. Any help will be appreciated Thanks
1 Answer 1
The problem is unrelated to sockets. You specify a buffer of 20 bytes (data[:20]) yet you ask to extract 24 bytes from it (struct.unpack('IILQ',...), hence
struct.error: unpack requires a buffer of 24 bytes
But, doesn't the documentation claim that it should be 20 bytes in total, i.e. 4 bytes for I, 4 bytes for L and 8 bytes for Q?
This is only true for "standard" encoding, which need to be explicitly enforced using the = prefix (or < or >), i.e. =IILQ instead of IILQ. Without a prefix enforcing standard encoding it will be native encoding, which is likely 8 byte for L on your system.
3 Comments
"=IILxxxxQ".struct.pack('L',0x0102030405060708) and observe that all of the 8 bytes actually end up in the response -> b'\x08\x07\x06\x05\x04\x03\x02\x01'. This means L is taking the full 8 bytes. Also, why would the native alignment for a 4 byte I be at 4 byte while for a presumably 4 byte L at 8 byte?struct.error: argument out of range (3.9) / struct.error: 'L' format requires 0 <= number <= 4294967295 (3.12). The Q gets aligned to multiples of 8 and padding is inserted before it, try struct.pack('BQ',0xFF, 0x0102030405060708)
pack('dbdbddd', ...)which is 56 bytes butstruct.unpack('10096s', ...)which is 10096 bytes.