2010-04-19 15 views
6

Estoy escribiendo un programa que usa QUdpSocket para transmitir datos a través de la red. Este es mi primer programa de socket y me he encontrado con un problema interesante llamado Endianness.Qt Sockets and Endianness

Mi pregunta real en, ¿tengo que preocuparme por Endianness cuando estoy usando QNetwork como mi biblioteca de sockets? Si tengo que preocuparme, ¿qué debo hacer para evitar adecuadamente los problemas de Endianness?

Gracias de antemano.

Respuesta

11

En general, debe preocuparse por la endianidad (orden de bytes) cuando transfiere enteros mayores que un solo byte de una computadora a otra. En C/C++, esto significa que si está enviando algo así como un entero de 16 bits, 32 o 64 bits, primero debe convertir el número entero a orden de bytes de red, (también conocido como Big-Endian) La computadora en el extremo receptor debe convertir los enteros entrantes a orden de bytes del host, que es el orden por bytes que el host-machine usa de forma nativa. Esto generalmente se hace usando la serie de funciones de biblioteca htons y ntohs, pero con la biblioteca Qt también puede usar las funciones qToBigEndian y qFromBigEndian.

Tenga en cuenta que no necesita preocuparse por la endianidad al enviar texto ASCII o UTF-8, ya que estos formatos están compuestos de secuencias de bytes individuales, en lugar de tipos de datos de varios bytes.

+0

No siempre es necesario o sensato hacer esto, si estuviera transmitiendo video o no tendría sentido convertir cada byte en htons y luego volver de nuevo; sería mejor tener un código para que la máquina receptora supiera en qué dirección estaban los datos. –

+0

Incorrecto, UTF-8 es una codificación de ancho variable, garantiza que representa todos los caracteres Unicode y puede tomar hasta 4 bytes. –

+0

No, su comprensión es incorrecta. UTF-8 es la codificación de ancho variable, pero no se ve afectada por endianness porque los caracteres de longitud variable se componen de secuencias de bytes ordenadas, a diferencia de UTF-16 o UTF-32 donde la unidad más pequeña es un entero binario de 2 (o 4) bytes cuyo orden de bytes está determinado por la arquitectura endianness. –

2

Si está transfiriendo datos binarios entre dos máquinas con una endianess diferente, puede que tenga que preocuparse.

El conector de red enviará los datos sin cambios. Si las otras máquinas suponen que los bytes que se enviaron están en un orden particular, debe gestionarlo.

Si está transfiriendo datos en un formato conocido, como una imagen, entonces el formato de imagen generalmente tiene algo en el encabezado para mostrar el orden en que fue escrito y la biblioteca lectora/escritora lo manejará. Si está inventando su propio formato binario, entonces depende de usted. También puede que tenga que considerar el tamaño, ¿cuántos bytes es un int en la otra máquina?

La buena noticia es que la mayoría de las máquinas son Intel y para la mayoría de las aplicaciones, el envío de pequeñas cantidades de datos en formato ascii funcionará.

0

CPUs Intel usan poco endian. La mayoría de todo lo demás es Big Endian. El orden de bytes de red predeterminado es big endian.

Para comprobar si la endianidad es un problema, envíe el valor 0x12345678 y compruebe si lo hace igual o 0x78563412. Si el valor en la computadora receptora es el valor posterior, entonces la endianidad no es la misma entre los dos sistemas.

Compruebe this wikipedia article para obtener información sobre endianness.

+0

Intel CPUS usa little endian; no es una función del sistema operativo. –

+3

Es engañoso decir que Windows usa little endian, y "todo lo demás" usa Big Endian. Endianness es una propiedad de la arquitectura del procesador, no del sistema operativo. La mayoría de las computadoras domésticas son pequeñas endian porque los procesadores Intel y AMD x86 son poco endian. Esto incluye máquinas x86 que ejecutan Linux u otro sistema operativo además de Windows. –

+0

Sí, las computadoras Intel son pequeñas endian, PowerPC eran big endian (el chip es conmutable pero Mac usó el modo nativo), ARM (iStuff) es la implementación definida –

1

Aquí es una prueba sencilla para el gran orden de bits, en caso de que desee:

// Esta prueba supone un tamaño de al menos int 2.

static const int testValue = 1;

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

bool CD_is_bigendian (void) { is_bigendian retorno(); }

+0

Para aquellos que hacen referencia a esto en el futuro, puede pensar que lo quiere, pero usted no en realidad: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html – josaphatv

1

Sé que esto fue respondido hace mucho tiempo, pero pensé que lo agregaría.

En lugar de utilizar las funciones de conversión endian, se puede utilizar la funcionalidad QDataStream (con cualquier QIODevice), que es mucho más fácil e intuitiva en mi opinión. Por supuesto, eso lo encerraría en el uso de QDataStream tanto en el emisor como en el receptor, pero vale la pena en ese caso.

Ejemplo de uso, para la muestra de otra persona de enviar una imagen:

QDataStream & operator<< (QDataStream& stream, const QImage& image);
QDataStream & operator>> (QDataStream& stream, QImage& image);
(Tanto de los que ya están implementados dentro de Qt.)

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