¿Puedo ignorar con seguridad el orden de bytes en la red?

24

Estoy desarrollando una aplicación servidor-cliente donde el cliente se ejecutará en Windows y el servidor probablemente en Linux. Tal vez luego transfiera el cliente a Mac y Linux, pero aún no.

Todos los equipos domésticos en estos días funcionan con little-endian. Busqué en Google por un tiempo, pero realmente no pude encontrar una lista de dispositivos que se ejecutan en big-endian. Hasta donde sé, algunos chips Motorola todavía usan big-endian y tal vez algunos teléfonos (no planeo portar la aplicación a teléfonos inteligentes, así que esto no me importa). Entonces, ¿por qué reorganizaría los bytes de cada entero, cada corto, cada flotante, doble, etc., para leer y escribir , cuando ya que tanto el servidor como el cliente se ejecutan en little-endian?

Eso es solo un trabajo innecesario que hacer. Entonces, mi pregunta es: ¿puedo ignorar con seguridad el endianness y simplemente enviar datos little-endian? ¿Cuales son las desventajas?

tkausl
fuente
44
¿Cómo sabrán las máquinas si están recibiendo datos little-endian en lugar de los datos big-endian habituales / estándar?
Ixrec
2
Debe distinguir entre los metadatos que requiere el protocolo de red y la carga útil, que es solo un conjunto de bytes no interpretados para todos, excepto su código. Espero que no estés rodando tu propia pila de redes. En consecuencia, supongo que la pregunta es solo sobre la carga útil, ¿correcto?
2
@delnan sí, solo hablando de la carga útil. Por supuesto, todavía hablaré en orden de bytes de red con la pila de red.
tkausl
3
Solo un pensamiento al margen: ¿Es realmente necesario que trabajes en un nivel de abstracción donde la endianness es una preocupación? Puede valer la pena considerar el uso de protocolos para los cuales existen bibliotecas apropiadas que encapsulan todo este "desorden" de bajo nivel. Luego, también tiene la ventaja adicional de que agregar más clientes se puede hacer mucho más fácilmente.
godfatherofpolka
1
@tkausl Solo dos pensamientos adicionales: como regla general, IO es extremadamente lento en comparación con los cálculos, por lo que cualquier sobrecarga introducida al trabajar en un nivel de abstracción más alto es probablemente insignificante. Incluso podría suceder que algunas bibliotecas superen las implementaciones manuales debido a la combinación inteligente de recursos y el manejo asincrónico, etc. Entonces, primero evaluaría cuidadosamente las soluciones existentes. Además, dada su descripción, también me gustaría reflexionar sobre la escalabilidad en lugar del rendimiento, aquí podría volver a beneficiarse del uso de protocolos de nivel superior.
godfatherofpolka

Respuestas:

29

... ¿por qué debería reorganizar los bytes ... cuando ya sé que tanto el servidor como el cliente se ejecutan en little endian? Eso es un trabajo innecesario que hacer.

Solo es innecesario si puede garantizar que su código siempre se ejecutará en arquitecturas little-endian. Si tiene la intención de que tenga una larga vida, vale la pena el esfuerzo adicional para evitar perturbar el código bien probado dentro de una década, cuando alguna arquitectura big-endian se ha convertido en lo "in" y considera que es un buen mercado para su aplicación.

Hay un orden de bytes estándar de red. Es big-endian, pero nada dice que tenga que cumplirlo al diseñar su protocolo. Si sabe de antemano que la mayoría de los sistemas que ejecutan su código serán poco endian y el rendimiento es crítico, declare que el "orden de bytes estándar tkausl" y vaya con él. Donde normalmente llamaría htons()para poner las cosas en el orden que necesita, escriba una macro llamada htots()que compila condicionalmente nada en arquitecturas little-endian y hace la reorganización en big-endian.

Mantener el código para realizar las conversiones entrantes y salientes no es realmente un gran esfuerzo. Si tiene una gran cantidad de mensajes, busque la forma de expresarlos y escriba un programa para generar las conversiones entrantes y salientes.

Blrfl
fuente
10
La redacción when designing your protocoles importante, porque también dice implícitamente que esta opción solo existe cuando se diseña un nuevo protocolo y no cuando se implementa algún protocolo existente. Y al mencionar la necesidad de una htots(y realmente una familia completa de funciones), también deja en claro que elegir un orden de bytes diferente no es algo que se hace para simplificar el código, pero podría hacerlo un poco más rápido.
kasperd
44
Hay funciones (no estándar pero muy comunes en estos días) htole32() , htole16(), le16toh(), etc., funciones disponibles también. Lamentablemente, el archivo que se debe incluir para declararlos es aún menos estándar: <endian.h>o <sys/types.h>depende de la plataforma.
torek
Esta respuesta está bien, pero creo que la suposición de que el rendimiento podría ser crítico en el caso dado es probablemente una suposición errónea, basada más en la superstición que en los hechos.
Doc Brown
1
@DocBrown: Siempre me gusta señalar que el protocolo X ha apoyado la elección de su propio orden de bytes durante 30 años, y tan ajustados como estaban los recursos en ese momento, nadie se quejó de que fuera un problema.
Blrfl
7

Es tu protocolo.

No puedes ignorarlo con seguridad. Pero puedes etiquetarlo con seguridad. Usted controla el cliente y el servidor. Tú controlas el protocolo. ¿No tiene sentido no preocuparse si es big-endian o little-endian siempre y cuando sepas si ambas partes están de acuerdo?

Esto significa gastos generales. Ahora tienes que marcar tu endianness de alguna manera. Haz eso y puedo leerlo en cualquier cosa.

Si no desea una sobrecarga de datos, y su CPU está aburrida y busca algo que hacer, entonces conéctese .

naranja confitada
fuente
6

Entonces, mi pregunta es: ¿puedo ignorar con seguridad la endianess y simplemente enviar datos little-endian?

Hay dos interpretaciones de eso:

  • Si diseñas tus aplicaciones / protocolos para siempre 1 Enviar ascendente hacia la izquierda, entonces usted no está haciendo caso omiso endianess.

  • Si diseña sus aplicaciones / protocolos para enviar / recibir cualquiera que sea la endianess nativa, funcionarán siempre que ejecute sus aplicaciones en plataformas con la misma endianess nativa.

    ¿Es eso "seguro" 2 ? ¡Eso es para que juzgues! Pero ciertamente hay plataformas de hardware comunes que usan little-endian, big-endian o ... bi-endian.

    Referencia:

¿Cuales son las desventajas?

La desventaja obvia de ignorar la endianess es que si usted / sus usuarios necesitan ejecutar sus aplicaciones / protocolos entre plataformas con diferente endianess nativa, entonces tienen un problema. Las aplicaciones se interrumpirán y deberá cambiarlas para solucionar el problema. Y lidiar con problemas de compatibilidad de versiones, etc.

Claramente, la mayoría de las plataformas de generación actual son nativamente little endian, pero 1) algunas no lo son, y 2) solo podemos adivinar lo que sucederá en el futuro.


1 - Siempre ... incluso en plataformas que son nativas big-endian.

2 - De hecho, ¿qué significa "seguro"? Si nos pide que pronostiquemos la dirección futura de las plataformas de hardware ... me temo que no se puede responder objetivamente.

Stephen C
fuente
3

Endianness no es la única consideración. Existe el tamaño de los enteros, hay un paquete de estructuras que es posible que desee enviar o recibir, y así sucesivamente.

Puedes ignorar todo esto. Nadie puede forzarte. Por otro lado, la forma segura y confiable es documentar un formato externo y luego escribir código que lea o escriba el formato externo correctamente, sin importar cuál sea su procesador, su lenguaje de programación y la implementación de su lenguaje de programación.

Por lo general, no es mucho código. Pero tiene un gran beneficio: las personas que leen su código no sospecharán que no tiene idea, no saben nada sobre el intercambio de datos externos y escriben código en el que generalmente no se puede confiar.

gnasher729
fuente
3

La pila de red BSD estándar en C tiene la funcionalidad hton/ ntoh( network-to-host/ host-to-network) que se expande a no-ops en máquinas nativas de red (big endian). Necesitaría sus propias contrapartes para el escenario en el que el orden de bytes nativo de la red es poco endian.

Esa es la forma sólida de hacerlo.

Sería poco convencional, pero no veo nada de malo en ello. Las computadoras en red siempre obtienen pruebas y necesitan acordar protocolos sobre cómo interpretar esos bytes. Esto es solo parte de eso.

PSkocik
fuente
3

Varios protocolos utilizados para transmitir datos entre servidores usan pequeños números endian:

  1. BSON
  2. Buffers de protocolo
  3. Capn Proto

Consulte https://en.wikipedia.org/wiki/Comparison_of_data_serialization_formats , para obtener detalles sobre varios formatos, algunos de los cuales tienen números little-endian y otros tienen números big-endian.

No hay absolutamente nada de malo en usar un protocolo basado en pequeños números endianos. Una máquina endian grande es tan capaz de leer números endian pequeños como una máquina endian pequeña puede leer números endian grandes. Muchas personas lo han hecho específicamente para evitar el costo de cálculo adicional de decodificar números big-endian en máquinas little endian.

Si construye su protocolo sobre uno de estos protocolos existentes, entonces ni siquiera tiene que preocuparse por el problema usted mismo, ya está solucionado. Cuando decida ejecutar su código en una plataforma big-endian, las bibliotecas que implementan estos protocolos se encargarán automáticamente de garantizar que decodifique los valores correctamente.

Winston Ewert
fuente
2

Un ejemplo de un gran sistema endian es el MIPS utilizado en los enrutadores. Tanto ARM como MIPS son intercambiables por endian, pero a menudo MIPS es big endian porque facilita el hardware de la red (la parte más importante de una palabra es la parte que recibe primero y puede tomar una decisión de enrutamiento antes de que haya recibido el resto de la palabra, en lugar de tener que amortiguar toda la palabra).

Por lo tanto, depende de lo que quiera decir con 'Linux', pero si alguna vez desea ejecutar su aplicación de servidor en un sistema más pequeño como un enrutador que ejecuta OpenWRT, entonces puede que tenga que considerar el soporte de Big Endian.

Como de costumbre, hacer suposiciones simplificadoras es una optimización perfectamente sensata hasta el momento en que golpeas algo que no se ajusta a las suposiciones. Solo usted puede decir cuán doloroso sería relajarlos si alguna vez se encuentra con ese problema.

usuario1908704
fuente
0

No creo que ninguna de las respuestas sea lo suficientemente precisa. Según Wikipedia, la endianidad es el orden de bytes que comprende una palabra.

Tomemos 4 bytes e interpretemos como int. En un pequeño sistema endian, los bytes se interpretarán de derecha a izquierda y viceversa en un sistema endian grande. Obviamente, es importante acordar en qué extremo interpretar un int.

Alejémonos un poco de los protocolos de red modernos que podrían estar usando json o xml. Ninguno de esos formatos transferirá un int como 4 bytes. Transferirán los datos como texto que se analizará como un int en el lado receptor.

Entonces, al final, la endianness no importa cuando se usa json o xml. Todavía necesitamos usar big endian para los encabezados tcp, por eso se llama orden de bytes de red, pero la mayoría de los programadores no necesitan meterse con ellos a diario.

La codificación más utilizada en la actualidad es la utf-8, que también es inmune a los problemas relacionados con la endianidad .

Entonces diría que sí. Es seguro ignorar la endianidad cuando se usan formatos basados ​​en texto transferidos usando utf-8.

Esben Skov Pedersen
fuente
dos votos negativos y sin comentarios. Excelente.
Esben Skov Pedersen
1
Yo no era el votante, pero esta respuesta parece ignorar / descartar una pregunta perfectamente válida. El hecho de que algunos protocolos estén basados ​​en texto no significa que todos los protocolos deberían estarlo.
Peter Green
2
Voté esto porque toca el hecho de que el formato de carga no tiene nada que ver con los protocolos subyacentes. A algunas personas les encanta indagar en problemas inventados.
Zdenek
0

Los grandes sistemas endianos parecen estar saliendo. Muchos de los Unix tradicionales usaron Big Endian, pero han estado en declive durante años a favor de Linux en x86.

arm es bi-endian, pero la variante big endian parece raramente verse.

mips existe en ambas variantes. Adfaict, la variante big endian se ve principalmente en aplicaciones de red (por razones históricas, los protocolos de internet generalmente usan big endian).

ppc era tradicionalmente big endian con algunas partes compatibles con ambos endian, pero IBM parece ahora estar presionando el modo little endian para ppc de 64 bits (recientemente empujaron puertos ppc64el en Debian y Ubuntu).

sparc es normalmente big endian pero nuevamente parece estar en declive.

Si está implementando un protocolo existente, entonces obviamente debe seguir sus especificaciones. Si desea que el IETF bendiga su nuevo protocolo, es probable que big endian sea más fácil porque eso es lo que ya usan en sus protocolos existentes, pero la OMI para un nuevo diseño de protocolo "greenfield" little endian es el camino a seguir.

Puede poner macros desde el principio, que serán no operativos en pequeños sistemas endian o no puede molestarse hasta / a menos que necesite portar a un gran sistema endian.

Peter Green
fuente