2010-04-19 17 views
6

Sto scrivendo un programma che utilizza QUdpSocket per la trasmissione di dati attraverso la rete. Questo è il mio primo programma di socket e mi sono imbattuto in un problema interessante chiamato Endianness.Qt socket ed endianness

La mia domanda attuale, devo preoccuparmi di Endianness quando sto usando QNetwork come libreria dei miei socket? Se devo preoccuparmi, cosa devo fare per evitare correttamente i problemi di Endianness?

Grazie in anticipo.

risposta

11

Generalmente, è necessario preoccuparsi dell'endianità (ordine byte) quando si trasferiscono numeri interi maggiori di un singolo byte da un computer a un altro. In C/C++, questo significa che se stai inviando qualcosa come un intero a 16 bit, 32 bit o 64 bit, devi prima convertire il numero intero in ordine byte di rete, (noto anche come Big-Endian). Il computer sul lato ricevente deve quindi convertire i numeri interi in entrata nell'ordine di byte dell'host , che è l'ordine in byte utilizzato dall'host in modo nativo. Di solito questo viene fatto usando la serie htons e ntohs di funzioni di libreria, ma con la libreria Qt è anche possibile utilizzare le funzioni e qFromBigEndian.

Si noti che non è necessario preoccuparsi di endianness durante l'invio di testo ASCII o UTF-8, perché questi formati sono composti da sequenze di singoli byte, piuttosto che tipi di dati multi-byte.

+0

Non è sempre necessario o ragionevole farlo, se tu fossi in streaming vide o non avrebbe senso convertire tutti i byte in htons e poi tornare indietro - sarebbe meglio avere un codice in modo che la macchina ricevente sapesse da che parte stavano i dati. –

+0

Wrong, UTF-8 è una codifica a larghezza variabile, garantita per rappresentare ogni carattere Unicode e può quindi richiedere fino a 4 byte. –

+0

No, la tua comprensione non è corretta. UTF-8 è una codifica a larghezza variabile, ma non è influenzata da endianness perché i caratteri a lunghezza variabile sono composti da sequenze di byte ordinate, a differenza di UTF-16 o UTF-32 dove l'unità più piccola è un intero binario di 2 (o 4) byte il cui ordine dei byte è determinato dall'architettura endianness. –

2

Se si trasferiscono dati binari tra due macchine con un endianess diverso, potrebbe essere necessario preoccuparsi.

Il socket di rete invierà i dati invariati. Se le altre macchine presuppongono che i byte che sono stati inviati sono in un ordine particolare, devi gestirlo.

Se si trasferiscono dati in un formato noto, ad esempio un'immagine, il formato dell'immagine in genere ha qualcosa nell'intestazione per indicare l'ordine in cui è stato scritto e la libreria del lettore/scrittore lo gestirà. Se stai inventando il tuo formato binario, allora è tutto per te. Potrebbe anche essere necessario considerare la dimensione, quanti byte è un int sull'altra macchina?

La buona notizia, la maggior parte delle macchine sono Intel e per la maggior parte delle applicazioni la spedizione di piccole quantità di dati in formato ASCII funzionerà.

0

Le CPU Intel utilizzano little endian. La maggior parte di tutto il resto è big endian. L'ordine dei byte di rete predefinito è big endian.

Per verificare se endianness è un problema, inviare il valore 0x12345678 e verificare se lo rende come lo stesso o 0x78563412. Se il valore sul computer ricevente è il valore successivo, quindi il endianness non è lo stesso tra i due sistemi.

Controllare this wikipedia article per informazioni su endianness.

+0

Intel CPUS usa little endian - non è una funzione del sistema operativo. –

+3

È fuorviante dire che Windows utilizza little endian e "tutto il resto" utilizza Big Endian. Endianness è una proprietà dell'architettura del processore, non del sistema operativo. La maggior parte dei computer domestici è poco endian perché i processori Intel e AMD x86 sono poco endian. Questo include macchine x86 che eseguono Linux o altri sistemi operativi oltre a Windows. –

+0

Sì Intel Mac è little endian, PowerPC è big endian (il chip è commutabile ma Mac è utilizzato in modalità nativa), ARM (iStuff) è definito dall'implementazione –

1

Ecco un semplice test per la grande endianness, nel caso in cui si desidera:

// Questo test assume una dimensione int di almeno 2.

statico const int testValue = 1;

#define is_bigendian() (((char) & testvalue) == 0)

bool CD_is_bigendian (vuoto) { ritorno is_bigendian(); }

+0

Per chi fa riferimento a questo in futuro, potresti pensare di volerlo, ma non lo fai in realtà: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html – josaphatv

1

So che è stata una risposta molto tempo fa, ma ho pensato di aggiungere altro.

Invece di usare le funzioni di conversione endian, è possibile utilizzare la funzionalità QDataStream (con qualsiasi QIODevice), che è molto più più semplice e intuitivo a mio parere. Ovviamente, questo ti bloccherebbe nell'usare il QDataStream sia sul mittente che sul ricevente, ma ne valeva la pena per quel caso.

Esempio di utilizzo, per il campione di qualcun altro di inviare un'immagine:

QDataStream & operator<< (QDataStream& stream, const QImage& image);
QDataStream & operator>> (QDataStream& stream, QImage& image);
(Sia di coloro che sono già implementati all'interno di Qt.)

QTcpSocket *tcp = ...;
QImage img = ...;
QDataStream(tcp) << img;