3

I am new to tcp, and have set up two applications, one in c++ that sends data, and one in c# that receives it. I send two float arrays, each containing three floats.

The data transfers, and unpacks fine, but the order of the data does not stay consistent. For example, I send float1, float2, float3, and receive float2, float1, float3.

My applicable c++ is:

float position[3];
float rotation[3];

for (int i = 0; i < 3; i++)
        {
            iResult = send(ConnectSocket, (char*)&position[i], (int) sizeof(float),4);
            iResult = send(ConnectSocket, (char*)&rotation[i], (int) sizeof(float),4);
        }
        if (iResult == SOCKET_ERROR) {
            printf("send failed with error: %d\n", WSAGetLastError());
            closesocket(ConnectSocket);
            WSACleanup();
            //return 1;
        }

and c#:

clientSocket = serverSocket.Accept();
Console.WriteLine("Server: Accept() is OK...");
Console.WriteLine("Server: Accepted connection from: {0}", clientSocket.RemoteEndPoint.ToString());

                            // Receive the request from the client in a loop until the client shuts
                            //    the connection down via a Shutdown.
                            Console.WriteLine("Server: Preparing to receive using Receive()...");
                            while (true)
                            {
                                rc = clientSocket.Receive(receiveBuffer);
                                float transX = System.BitConverter.ToSingle(receiveBuffer, 0);
                                float transY = System.BitConverter.ToSingle(receiveBuffer, 4);
                                float transZ = System.BitConverter.ToSingle(receiveBuffer, 8);

                                float rotX = System.BitConverter.ToSingle(receiveBuffer, 12);
                                float rotY = System.BitConverter.ToSingle(receiveBuffer, 16);
                                float rotZ = System.BitConverter.ToSingle(receiveBuffer, 20);


                                Console.WriteLine(transX + " " + transY + " " + transZ + "\n");
                                Console.WriteLine(rotX + " " + rotY + " " + rotZ + "\n");
                               // Console.WriteLine("Server: Read {0} bytes", rc);
                                if (rc == 0)
                                    break;
                            }

What is my error here? Should I be sending the floats individually? Thanks.

2 Answers 2

4

The first error is to assume that you'll receive the data exactly as you've sent it.

Unfortunately, when sending several floats, the receiver may receive them all together (as you expect), but it could as well receive them in several pieces (down to byte by byte in an hypothetical worst case).

So in you while loop you may for example receive 10 bytes only but you suppose to have received 24. Leading to a lot of garbage.

Solution: check with rc that you've received the right amount of data before assuming it's there, and implement the loop in a way to properly manage buffer (i.e. the end of receiving of the first group of data, might come together with the begin of the next sequence).

There's a second more subtle issue: your code logic works only if the source and the target use the same floating point encoding. The C++ standard doesn't fix this encoding (it's frequently IEEE-754 but it doesn't have to be, and even if it is, different endianness could affect the order of the bytes send over the network).

This may not be a problem if you target only with wintel platform. But I think it's worth to mention in case your C++ part is for an IoT device using a different architecture ;-)

Edit: hint for processing buffered reception

I'm not fluent in C#, but the principle would be something like:

    Console.WriteLine("Server: Preparing to receive using Receive()...");
    rc=1; 
    br=0;  // number of bytes in buffer  
    sf=24; // size of one sequence to be received
    while (true)
    {
        while (br<sf && rc>0) { // fill buffer until all bytes of one sequence are there
            rc = clientSocket.Receive(receiveBuffer, br, sf-br,SocketFlags.None);
            br += rc; 
        }             
        if (rc == 0) {
            if (br>0) 
                  Console.WriteLine("Server: interupted while receiving data...");
               break;
        }
        //... here you can convert the content of the buffer 
    }
Sign up to request clarification or add additional context in comments.

8 Comments

thank you! So i can add 'if (rc == 24)'... What would recommend to manage the buffer? Can I add some kind of end marker/character ?
Whether or not you use a separator will not fundamentally change the way you'll loop. You need to keep track in the buffer of the position where to put the next chunk of data to be received. As soon as the length of data in buffer is 24 OR MORE, you can perform your conversion. Then you have to move the remainder of the buffer at the beginning, so to be able to complete the next chunk of data (that's because of the possible overlap with the next sequence of floats).
Sorry I thought I had this, but am still getting the value switching. Are you able to point me in the right direction to move the remainder of the data to the beginning? Thank you again!
I'm not so fluent in C#, but Array.Copy() as explained here, should do the trick.
I've edited, and I suggest to use of receive with additional arguments. By limiting the max size argument to 24, it simplifies things avoiding moving parts of the buffer.
|
3

The order you're sending your floats in is like so:

pos1
rot1
pos2
rot2
pos3
rot3

However, when receiving them, you're processing the data like this:

pos1
pos2
pos3
rot1
rot2
rot3

The solution here would be to read the floats from the right indices.

float transX = System.BitConverter.ToSingle(receiveBuffer, 0);
float transY = System.BitConverter.ToSingle(receiveBuffer, 8);
float transZ = System.BitConverter.ToSingle(receiveBuffer, 16);

float rotX = System.BitConverter.ToSingle(receiveBuffer, 4);
float rotY = System.BitConverter.ToSingle(receiveBuffer, 12);
float rotZ = System.BitConverter.ToSingle(receiveBuffer, 20);

1 Comment

ah, thank you! This(obviously) has put them in the correct order. However, they do not stay in the same order. when I print the above in a loop, i see pos1, pos2, pos3, then the next loop will give pos2, pos1, pos3, and so on.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.