Socket communication: Sometimes I received long messages in parts

Hi!
I am working on a project with several Atlas Copco controllers and I control all those Atlases with socket communication in Ignition..
I send and receive several messages from those Atlas (communication enable, program send and receive, socket bit selector, result message, keep alive message, ETC).
Everything works fine, but sometimes when I receive the result message, I receive it in parts.
It is a large message (386 characters), all other messages are less than 100 characters. I think my problem is in the way I decode the data. Any idea how to improve this?

This is the code to get the message, I think the "If data:" is the problem, because I decode the message without ensuring that it is complete.
But I repeat, I only have problems when I receive message 061 (386 characters).

get_message(client_socket, controller_id):
    try:
        while True:
            data = client_socket.recv(1024) #MAYBE HERE IS THE PROBLEM????
            if data:
                returndata = data.decode('utf-8')
                if returndata [4:8] != "9999":	#dont print keep alive (9999)
                	print("Mensaje recibido del {}: N° Caracteres {} - {}".format(controller_id, len(returndata), returndata))
                process_data(returndata, controller_id)
    except Exception as e:
        print("Error de E/S: {}".format(e))

This is an example of the problem, I first receive 256 characters and then the rest.

This is another example, first I receive 64 characters, then 128, then 192, and then 2.
In the second result I first receive 320 and then 66 (in my programming I have that if I receive more than 220 characters I proceed with the script because the atlas result is within the first 220 characters).

And this is a good example, here I get the 386 characters on the first try.

If I dont send an acknowledgement (message 062) to the Atlas controller, the controller sends the message again, so I do not lose the result, but the problem is that it takes several seconds to send the result again and a lot of cycle time is lost.

I know it's a lot of text but I hope I can find the solution here, thank you very much!

(post deleted by author)

You don't seem to be doing anything to accumulate data in get_message when the all of the data you need doesn't arrive at once. You just throw it away, and then on the next loop iteration you receive new data, and pass only that new data into your process_data function.

1 Like

ACOP frames have a header, and the first 4 bytes of the header are the overall frame length.

You could use this to eliminate the heuristic guessing you're doing all over the place and know exactly how much data to read.

This is untested:

while True:
    # Read the first 4 bytes
    buffer = ''
    while len(buffer) < 4:
        data = client_socket.recv(4 - len(buffer))
        if not data: 
            # TODO handle disconnected client
            break
        
        buffer += data

    # First 4 bytes are ASCII-encoded length
    length = int(buffer)

    # Accumulate data until length + 1 
    # (length does not include NULL terminator byte)
    while len(buffer) < length + 1:
        data = client_socket.recv(length + 1 - len(buffer))
        if not data: 
            # TODO handle disconnected client
            break

        buffer += data

    # Process the data
    process_data(buffer)
2 Likes

This is brilliant!! I'll try it tomorrow, thanks!

I've already tested this code and it actually works pretty well. I've done a lot of torques with "bad result" (because it's the fastest way to test) and I always get 386 characters.

And obviously it also works with good results, and with the rest of the messages in the atlas.
Really, thank you very much!!!