2010-09-20 32 views
3

我有一个非常奇怪的错误。通过TCP/IP传输float值和数据损坏

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

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

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

该错误是:有时会出现一些由应用B接收的浮点值的不相同,通过应用A发送

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

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

这些值在发送之前和接收之后立即被记录。

的代码是非常简单的:该消息协议有一个4字节的报头是这样的:

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

当我收到消息“方向”,有时“方位角”值是从所述一个通过发送不同服务器!

数据不应该一直保持不变吗? TCP/IP不保证数据的传输没有损坏?数学协处理器中的例外情况是否会影响TCP/IP协议栈?是我收到一小部分字节(4字节)然后是消息体的问题吗?

编辑:

的问题是在字节顺序交换程序。下面的代码交换的特定浮子的字节序周围,然后再次交换它并打印字节:

#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 BF 7F CA 26 BF

即浮点赋值可能使该值正常化,从而产生与原始值不同的值。

对此有任何意见。

EDIT2:

谢谢大家的回复。看起来问题是交换的浮点数在通过'return'语句返回时被推入CPU的浮点堆栈中。调用者然后弹出堆栈中的值,该值被舍入,但它是交换的浮点数,因此舍入会混淆该值。

+1

你应该检查些认同的答案关上你的一些其他问题。 – 2010-09-20 16:58:44

+1

请回头接受你的一些问题的答案。这是堆栈溢出用来鼓励人们回答额外问题的机制。 – atk 2010-09-20 16:59:07

+0

我该怎么做?我没有看到任何“接受”按钮。 – axilmar 2010-09-20 21:36:33

回答

0

您通过网络发送二进制数据,对结构布局使用实现定义的填充,因此只有在应用程序A和应用程序B都使用相同的硬件,操作系统和编译器时才能使用。

如果没关系,但是我看不出你的代码有什么问题。一个潜在的问题是,您使用ntohs来提取消息的长度,并且该长度是总长度减去标题长度,所以您需要确保正确设置它。它需要做的

msg.length = htons(sizeof(ORIENTATION_MESSAGE) - sizeof(MESSAGE_HEADER)); 

,但你不显示,设置了消息的代码...

+0

这不是填充。我使用#pragma pack(push,1),因此打包是1个字节。如果是填充,问题会立即显现。 – axilmar 2010-09-20 21:37:59

3

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

+0

是的,这些机器具有类似的CPU和操作系统,并且这两个程序都使用相同的代码库和编译器。 – axilmar 2010-09-20 21:37:21