sockets - 通过 TCP/IP 传输浮点值和数据损坏

标签 sockets tcp floating-point corruption packets

我有一个非常奇怪的错误。

我有两个应用程序通过 TCP/IP 进行通信。

应用A是服务端,应用B是客户端。

应用程序 A 每 100 毫秒向应用程序 B 发送一组浮点值。

错误如下:有时应用程序 B 接收到的某些浮点值与应用程序 A 传输的值不同。

最初,我认为以太网或 TCP/IP 驱动程序存在问题(某种数据损坏)。然后我在其他 Windows 机器上测试了代码,但问题仍然存在。

然后我在 Linux(Ubuntu 10.04.1 LTS)上测试了代码,问题仍然存在!!!

值在发送前和接收后记录。

代码非常简单:消息协议(protocol)有一个 4 字节的 header ,如下所示:

//message header
struct MESSAGE_HEADER {
    unsigned short type;
    unsigned short length;
};

//orientation message
struct ORIENTATION_MESSAGE : MESSAGE_HEADER
{
  float azimuth;
  float elevation;
  float speed_az;
  float speed_elev;
};

//any message
struct MESSAGE : MESSAGE_HEADER {
    char buffer[512];
};

//receive specific size of bytes from the socket
static int receive(SOCKET socket, void *buffer, size_t size) {
    int r;
    do {
        r = recv(socket, (char *)buffer, size, 0);
        if (r == 0 || r == SOCKET_ERROR) break;
        buffer = (char *)buffer + r;
        size -= r;
    } while (size);
    return r;
}

//send specific size of bytes to a socket
static int send(SOCKET socket, const void *buffer, size_t size) {
    int r;
    do {
        r = send(socket, (const char *)buffer, size, 0);
        if (r == 0 || r == SOCKET_ERROR) break;
        buffer = (char *)buffer + r;
        size -= r;
    } while (size);
    return r;
}

//get message from socket
static bool receive(SOCKET socket, MESSAGE &msg) {
    int r = receive(socket, &msg, sizeof(MESSAGE_HEADER));
    if (r == SOCKET_ERROR || r == 0) return false;
    if (ntohs(msg.length) == 0) return true;
    r = receive(socket, msg.buffer, ntohs(msg.length));
    if (r == SOCKET_ERROR || r == 0) return false;
    return true;
}

//send message
static bool send(SOCKET socket, const MESSAGE &msg) {
    int r = send(socket, &msg, ntohs(msg.length) + sizeof(MESSAGE_HEADER));
    if (r == SOCKET_ERROR || r == 0) return false;
    return true;
}

当我收到消息'orientation'时,有时'azimuth'值与服务器发送的值不同!

数据不应该一直都一样吗? TCP/IP 不保证数据的传递没有损坏吗?会不会是数学协处理器中的异常影响了 TCP/IP 堆栈?我先收到少量字节(4 个字节),然后收到消息正文,这是一个问题吗?

编辑:

问题出在字节顺序交换例程中。以下代码交换特定 float 的字节序,然后再次交换并打印字节:

#include <iostream>
using namespace std;

float ntohf(float f)
{
    float r;
    unsigned char *s = (unsigned char *)&f;
    unsigned char *d = (unsigned char *)&r;
    d[0] = s[3];
    d[1] = s[2];
    d[2] = s[1];
    d[3] = s[0];
    return r;
}

int main() {
    unsigned long l = 3206974079;
    float f1 = (float &)l;
    float f2 = ntohf(ntohf(f1));
    unsigned char *c1 = (unsigned char *)&f1;
    unsigned char *c2 = (unsigned char *)&f2;
    printf("%02X %02X %02X %02X\n", c1[0], c1[1], c1[2], c1[3]);
    printf("%02X %02X %02X %02X\n", c2[0], c2[1], c2[2], c2[3]);
    getchar();
    return 0;
}

输出是:

7F 8A 26 高炉 7F CA 26 BF

即 float 赋值可能会规范化该值,从而产生与原始值不同的值。

欢迎对此提出任何意见。

编辑2:

谢谢大家的回复。问题似乎是交换的 float 在通过“return”语句返回时被插入 CPU 的浮点堆栈。然后调用者从堆栈中弹出值,该值被四舍五入,但它是交换后的 float ,因此四舍五入弄乱了值。

最佳答案

TCP 尝试传送未更改的字节,但除非机器具有相似的 CPU 和操作系统,否则无法保证一个系统上的浮点表示与另一个系统上的浮点表示相同。您需要一种机制来确保这一点,例如 XDR 或 Google 的 protobuf。

关于sockets - 通过 TCP/IP 传输浮点值和数据损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3753641/

相关文章:

ios - UISlider值,转换为NSNumber,= -1.10311e-146

android - 检测 TCP 连接何时丢失

C++ TCP 服务器-客户端小问题

networking - Amazon S3 的奇怪 TCP 问题

networking - 使用 TUN/TAP 测试用户空间 TCP/IP 堆栈

java - 期望 n 个 float 总和为 1 的合适容差是多少

python - 从以两个十六进制字符串传输的 C double 转换

java - 如何在java中使接受的套接字成为非阻塞的

c++ - 如何在 Windows 中将套接字设置为阻塞模式?

c - 当套接字无效时