【问题标题】:Problems with sending float over network socket in C在 C 中通过网络套接字发送浮点数的问题
【发布时间】:2021-12-20 05:46:37
【问题描述】:

我有一个客户端,它在[0..10] 范围内生成一个随机浮点数。该客户端通过套接字将浮点值发送到服务器,服务器必须显示它。我一直在试图弄清楚如何通过套接字正确发送浮点数,但我无处可去。我设法直接发送值,但我想做的是将浮点数转换为网络表示并返回,所以我想使用函数 htonl()ntohl() 但我一直没有这样做。我不想在这里复制整个服务器/客户端代码,因为它相当多,所以我对发生的情况进行了一个小模拟,这会产生与服务器/客户端代码相同的问题。

#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;
}

这与我在服务器/客户端案例中想要的非常相似。如您所见,客户端将随机浮点数据复制到uint32_t 变量中,将其转换为网络表示并发送。服务器在uint32_t 类型的变量data 中接收该数据,将其转换为主机表示,并将该值转换为浮点数。我希望这行得通。但是当我运行它时,我会得到类似的东西:

Generated random float = 9.266754
After send: 1091847296.000000

或类似的东西。显然它不起作用。确切的行为发生在我的服务器/客户端代码中,我得到类似的输出。同样,在服务器/客户端代码中,每当我从网络表示中删除该转换并在我的机器上运行服务器和客户端代码时,一切都按预期工作,所以我很确定问题出在这个转换的某个地方,但我没有看不出上面的代码有什么问题。我在这里阅读了其他关于这种类型转换的问题(这就是我发现这种发送浮点数的方法的地方),但它们并没有解决我的问题。

【问题讨论】:

    标签: c sockets floating-point network-programming


    【解决方案1】:

    float res = (float) ntohl(data);

    您必须将这些位重新解释为浮点数,而不仅仅是将整数转换为浮点数。

    你可以例如做:

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

    假设您生成浮点数3.23。它具有二进制表示:010000000100111010111000010100101078900818。你做字节交换,你发送它,你再次交换字节。现在您有了原始表示,但您只需执行(float)1078900818,这就是“1078900818”。只是强制转换是行不通的,因为浮点数是IEEE-754 编码的。

    【讨论】:

    • 是的,这行得通。非常感谢。但是将位重新解释为浮点数和转换为浮点数之间有什么区别?我认为转换为浮点数正是如此,将来自该内存地址的位重新解释为浮点数。
    • 铸造一个浮点数,例如5.23 本质上是在点之前采取一切 (5.23->5)
    • 重新解释位意味着,您获取位并根据例如重新解释它们。 IEEE754标准
    • @abcxyz:强制转换执行转换,conversion 是一种操作,它采用一种类型的值并产生另一种类型或格式的结果,同时保留该值尽可能。例如,当我们将整数 3 转换为 float 时,结果是 float,值为 3。在相反的方向,将 3.25 转换为 int 产生 3,因为这是我们在 @987654331 中可以做的最好的事情@ 格式。同样,当我们将0x20 转换为十进制时,结果 32 具有相同的值。将 5 公斤转换为磅得到 11 磅,相同的值。
    • @abcxyz:有些转换与重新解释位混淆,但实际转换是在指针上执行的。如果我们有一个int *,一个指向int的指针,然后我们将它转​​换为float *,那么我们就有一个新类型的指针(指向float的指针),但它在意义上具有相同的值它指向相同的内存。如果编译器支持这些类型的别名,那么我们可以使用新指针来访问内存。该访问将这些位解释为float,但这是因为指针的类型指示编译器执行此操作。不是直接因为转换。
    猜你喜欢
    • 2013-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多