0

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

asked Feb 29, 2024 at 9:00
1
  • 1
    As said, either slice at 24 or change the format. The payload handling seems wrong too: you pack('dbdbddd', ...) which is 56 bytes but struct.unpack('10096s', ...) which is 10096 bytes. Commented Feb 29, 2024 at 12:22

1 Answer 1

2

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.

answered Feb 29, 2024 at 9:30
Sign up to request clarification or add additional context in comments.

3 Comments

Its not encoding, but alignment. Manual padding would be "=IILxxxxQ".
@ivvija: it's encoding - try 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?
Ok, so it can be both. On my PC (Win11) that fails 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)

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.