Domanda

Ho un estremamente strano bug.

Ho due applicazioni che comunicano su TCP / IP.

applicazione A è il server, e l'applicazione B è il client.

Application A invia una serie di valori decimali di applicazione B ogni 100 millisecondi.

Il problema è il seguente:. A volte alcuni dei valori float ricevuti dall'applicazione B non sono uguali ai valori trasmessi dall'applicazione A

Inizialmente, ho pensato che ci fosse un problema con il driver Ethernet o TCP / IP (una sorta di corruzione dei dati). Allora ho provato il codice in altre macchine Windows, ma il problema persisteva.

Ho poi testato il codice su Linux (Ubuntu 10.04.1 LTS) e il problema è ancora lì !!!

I valori vengono registrati poco prima di essere inviati e solo dopo che sono stati ricevuti.

Il codice è abbastanza semplice: il protocollo di messaggio ha un colpo di testa di 4 byte in questo modo:

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

Quando ricevo il messaggio 'orientamento', a volte il valore 'azimuth' è diverso da quello inviato dal server!

Qualora non i dati essere lo stesso per tutto il tempo? non fa il protocollo TCP / IP garanzia di consegna dei dati non corrotta? potrebbe essere che un'eccezione nel coprocessore matematico colpisce lo stack TCP / IP? si tratta di un problema che ricevo un piccolo numero di byte prima (4 byte) e poi il corpo del messaggio?

EDIT:

Il problema è nella routine endianess swapping. I seguenti swap codice del endianess di uno specifico galleggiante attorno, e poi swap nuovamente e stampa i byte:

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

L'output è:

7F 8A 26 BF 7F CA 26 BF

vale a dire. l'assegnazione galleggiante probabilmente normalizza il valore, producendo un valore diverso da quello originale.

Qualsiasi ingresso su questo è accolto favorevolmente.

EDIT2:

Grazie a tutti per le vostre risposte. Sembra che il problema è che il galleggiante scambiati, quando tornò con l'affermazione 'ritorno', viene spinto in pila virgola mobile della CPU. Il chiamante apre quindi il valore dalla pila, il valore è arrotondato, ma è il galleggiante scambiati, e quindi i pasticci arrotondando il valore.

È stato utile?

Soluzione

Si sta inviando dati binari attraverso la rete, usando imbottiture implementazione definiti per il layout struct, quindi questo sarà solo lavoro se si sta utilizzando lo stesso hardware, sistema operativo e compilatore sia per applicazione A e B di applicazione.

Se questo è ok, però, non riesco a vedere niente di sbagliato con il codice. Un potenziale problema è che si sta utilizzando ntohs per estrarre la lunghezza del messaggio e che la lunghezza è la lunghezza totale meno la lunghezza di testa, quindi è necessario assicurarsi che l'impostazione in modo corretto. Essa deve essere fatto come

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

ma non mostrano il codice che imposta il messaggio ...

Altri suggerimenti

TCP tenta di recapitare byte inalterati, ma meno che le macchine hanno CPU-s e operativi sistemi analoghi, non c'è alcuna garanzia che la rappresentazione virgola mobile in un sistema è identica a quella sull'altro. Avete bisogno di un meccanismo per assicurare questo, come XDR o Google di protobuf.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top