Home > Software design >  Problems with sending float over network socket in C
Problems with sending float over network socket in C

Time:11-07

I have a client which generates a random float number in the range [0..10]. This client sends the float value over a socket to the server and the server has to display it. I've been trying to figure out how to properly send a float over a socket and I can't get anywhere. I managed to directly send the value, but what I want to do is convert the float to network representation and back, so I want to use the functions htonl() and ntohl() but I keep failing to do so. I didn't want to copy the whole server/client code here since it's quite a bit so I produced a small simulation of what happens which creates the same problem as in the server/client code.

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char* argv[]) {

    uint32_t tmp, data;
    srand(time(NULL));
    float rand_float = ((float)rand() / (float)RAND_MAX) * 10;
    printf("Generated random float = %f\n", rand_float);

    // client converts to network representation(big endian) and sends the data
    memcpy(&tmp, &rand_float, sizeof(tmp));
    tmp = htonl(tmp);

    // simulate sending the data over the network
    memcpy(&data, &tmp, sizeof(data));

    // server receives the data and has to convert it to host representation (little endian in my case)
    float res = (float) ntohl(data);
    printf("After send: %f\n", res);

    return 0;
}

It's quite similar to what I want in the server/client case. As you can see, the client copies the random float data into a uint32_t variable, convert it to network representation and send it. The server receives that data in a variable data of type uint32_t, converts it to host representation and that value is cast to a float. I expected this to work. But when I run this I get something like:

Generated random float = 9.266754
After send: 1091847296.000000

Or something similar. Clearly it doesn't work. The exact behavior happens in my server/client code, I get similar output. Again, in the server/client code whenever I remove that conversion to and from the network representation and run the server and client code on my machine everything works as intended, so I'm pretty sure the problem lies somewhere in this conversion but I don't see anything wrong with the code above. I've read other questions here asking about this type of conversions (and that's where I found this method of sending floats) but they didn't solve my issue.

CodePudding user response:

float res = (float) ntohl(data);

You have to reinterpret the bits as float, not just cast the integer to float.

You could e.g. do:

float res = 0.0;
uint32_t tmp2 = ntohl(data);
memcpy(&res, &tmp2, sizeof(tmp2));

Suppose you generate the float 3.23. It has the binary representation: 01000000010011101011100001010010, or 1078900818. You do the byteswap, you send it, you swap the bytes again. Now you have the original representation, but you just do (float)1078900818, and this is simply "1078900818". Just casting doesn't work, as floating point numbers are IEEE-754 encoded.

  • Related