2009-02-08 16 views
8

Hola chicos, pregunta de un novato C/Redes ...Orden de los bytes con una gran variedad de caracteres en C

que estoy haciendo un poco de programación en C zócalo y tratando de luchar con problemas de orden de bytes. Mi solicitud (enviar) está bien, pero cuando recibo datos, mis bytes están fuera de servicio. Comienzo con algo como esto ...

char * aResponse= (char *)malloc(512); 
int total = recv(sock, aResponse, 511, 0); 

Cuando se trata con esta respuesta, cada palabra de 16 bits parece tener es bytes inversa (estoy usando UDP). Traté de arreglar que al hacer algo como esto ...

unsigned short * _netOrder= (unsigned short *)aResponse; 
    unsigned short * newhostOrder= (unsigned short *)malloc(total); 
    for (i = 0; i < total; ++i) 
    { 
     newhostOrder[i] = ntohs(_netOrder[i]); 
    } 

Esto funciona bien cuando estoy tratamiento de los datos como un resumen, sin embargo, si yo echo el puntero a un char de nuevo los bytes se invierten. ¿Qué estoy haciendo mal?

Gracias!

Respuesta

10

Ok, parece que hay problemas con lo que está haciendo en dos niveles diferentes. Parte de la confusión aquí parece derivar para su uso de punteros, a qué tipo de objetos apuntan, y luego la interpretación de la codificación de los valores en la memoria apuntada por el (los) puntero (s).

La codificación de entidades de múltiples bytes en la memoria es lo que se conoce como endianess.Las dos codificaciones comunes se conocen como Little Endian (LE) y Big Endian (BE). Con LE, una cantidad de 16 bits como un corto se codifica primero como el byte menos significativo (LSB). En BE, el byte más significativo (MSB) se codifica primero.

Por convención, los protocolos de red normalmente codifican cosas en lo que llamamos "orden de bytes de red" (NBO) que también es igual a BE. Si está enviando y recibiendo almacenamientos intermedios de memoria en plataformas de Big Endian, entonces no se encontrará con problemas de conversión. Sin embargo, su código dependería de la plataforma según la convención de BE. Si desea escribir código portátil que funcione correctamente en las plataformas LE y BE, no debe asumir la endialeza de la plataforma.

El logro de portabilidad endian es el propósito de rutinas como ntohs(), ntohl(), htons(), y htonl(). Estas funciones/macros se definen en una plataforma determinada para hacer las conversiones necesarias en los extremos de envío y recepción:

  • htons() - Convertir valor a corto de orden del anfitrión a fin de red (para enviar)
  • htonl() - Convertir el valor a largo de orden del anfitrión a fin de red (para enviar)
  • ntohs() - con vert valor a corto de orden de red para acoger fin (después de recibir)
  • ntohl() - Convertir el valor a largo del fin de la red para albergar fin (después de recibir)

entender que su comentario sobre el acceso a la la memoria cuando se regresa a los caracteres no afecta el orden real de las entidades en la memoria. Es decir, si accede al búfer como una serie de bytes, verá los bytes en el orden en que se codificaron en la memoria, ya sea que tenga una máquina BE o LE. Entonces, si está mirando un búfer codificado NBO después de recibirlo, el MSB será el primero, siempre. Si observa el búfer de salida después de haber convertido de nuevo a la orden de host, si tiene la máquina BE, la orden de bytes no cambiará. Por el contrario, en una máquina LE, todos los bytes se revertirán en el búfer convertido.

Finalmente, en su ciclo de conversión, la variable total se refiere a los bytes. Sin embargo, está accediendo al búfer como shorts. Su guardia de bucle no debe ser total, pero debe ser:

total/sizeof(unsigned short)

para dar cuenta de la naturaleza de doble byte de cada short.

0

el orden de bytes de la red es big endian, por lo que necesita convertirlo en little endian si quiere que tenga sentido, pero si solo es una matriz no debería hacer un escándalo, ¿cómo lo envía el remitente? datos?

+0

No, no * convierte a little endian, conviértalo a la orden local del host si desea que su programa sea portátil (el OP ni siquiera dijo cuál era su plataforma). Eso es exactamente para lo que son ntohs() y ntohl(). – bortzmeyer

3

Esto funciona bien cuando estoy tratamiento de los datos como un resumen, sin embargo, si yo echo el puntero a un char de nuevo los bytes se invierten.

Eso es lo que esperaría.

¿Qué estoy haciendo mal?

Debes saber qué envió el remitente: saber si los datos son bytes (que no necesitan inversión), o cortos o largos (que sí lo hacen).

Google para las clases particulares asociados con los ntohs, htons y htons API.

2

No está claro qué representa aResponse (cadena de caracteres? Struct?). Endianness es relevante solo para valores numéricos, no char s. También debe asegurarse de que, al lado del remitente, todos los valores numéricos se conviertan de orden de bytes de host a red (hton*).

1

Aparte de su pregunta original (que creo que ya fue respondida), debería echarle un vistazo a su declaración malloc. malloc asigna bytes y un corto sin signo tiene más probabilidades de ser de dos bytes.

Su declaración debe verse como:

unsigned short *ptr = (unsigned short*) malloc(total * sizeof(unsigned short)); 
+0

No, 'total' ya se mide en bytes, por lo que no es necesario multiplicar por 2. Sin embargo, OP debe iterar de 0 a total/2, no de 0 a total. –

+0

Sí, tienes razón. Mi mal ... Tarde del domingo por la tarde :-) –

0

Para un solo byte, puede que no nos interese el orden de bytes.

Cuestiones relacionadas