necesita lo siguiente para enviar de forma portátil de estructura través de la red:
paquete de la estructura. Para compiladores gcc y compatibles, haz esto con __attribute__((packed))
.
No utilice ningún miembro que no sean enteros sin signo de tamaño fijo, otras estructuras empaquetadas que satisfagan estos requisitos o arreglos de alguno de los primeros. Los enteros con signo también son correctos, a menos que su máquina no use una representación de complemento de dos.
Decida si su protocolo usará codificación little-o big-endian de enteros. Haga conversiones al leer y escribir esos enteros.
Además, no tome los punteros de los miembros de una estructura empaquetada, excepto para aquellos con el tamaño 1 u otras estructuras empaquetadas anidadas. Ver this answer.
A continuación se muestra un ejemplo simple de codificación y decodificación.Supone que las funciones de conversión de orden de bytes hton8()
, ntoh8()
, hton32()
y ntoh32()
están disponibles (las dos anteriores son no operativas, pero hay coherencia).
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
// get byte order conversion functions
#include "byteorder.h"
struct packet {
uint8_t x;
uint32_t y;
} __attribute__((packed));
static void decode_packet (uint8_t *recv_data, size_t recv_len)
{
// check size
if (recv_len < sizeof(struct packet)) {
fprintf(stderr, "received too little!");
return;
}
// make pointer
struct packet *recv_packet = (struct packet *)recv_data;
// fix byte order
uint8_t x = ntoh8(recv_packet->x);
uint32_t y = ntoh32(recv_packet->y);
printf("Decoded: x=%"PRIu8" y=%"PRIu32"\n", x, y);
}
int main (int argc, char *argv[])
{
// build packet
struct packet p;
p.x = hton8(17);
p.y = hton32(2924);
// send packet over link....
// on the other end, get some data (recv_data, recv_len) to decode:
uint8_t *recv_data = (uint8_t *)&p;
size_t recv_len = sizeof(p);
// now decode
decode_packet(recv_data, recv_len);
return 0;
}
En lo que se refiere a las funciones de conversión de orden de bytes, de su sistema de htons()
/ntohs()
y htonl()
/ntohl()
se puede utilizar, para los enteros de 16 y 32 bits, respectivamente, para convertir a/desde big-endian. Sin embargo, no conozco ninguna función estándar para enteros de 64 bits, o para convertir a/desde little endian. Puede usar my byte order conversion functions; si lo hace, debe indicar el orden de bytes de su máquina definiendo BADVPN_LITTLE_ENDIAN
o BADVPN_BIG_ENDIAN
.
En lo que respecta a los enteros con signo, las funciones de conversión se pueden implementar de forma segura como las que escribí y vinculé (intercambiando bytes directamente); simplemente cambie unsigned a signed.
ACTUALIZACIÓN: si quieres un protocolo binario eficiente, pero no le gusta tocar el violín con los bytes, puede intentar algo así como Protocol Buffers (C implementation). Esto le permite describir el formato de sus mensajes en archivos separados y genera el código fuente que usa para codificar y decodificar mensajes del formato que especifique. También implementé algo similar, pero muy simplificado; vea my BProto generator y some examples (busque en los archivos .bproto, y addr.h para el ejemplo de uso).
probaré este método, solo quiero preguntar qué pasa si solo uso sprintf y escribo todos los datos en cadena usando un delimitador para separar los elementos de la estructura y enviarlos a través del socket y luego uso strtok para extraer cada elemento el otro lado ? ¿Esta sería una solución viable también? – user434885
sí, sprintf funcionará, pero * solo * para enteros; si quisiera enviar una cadena (es decir, una matriz de bytes sin procesar), con este método, tendría que tratarlos como una matriz de bytes y convertir cada byte en un entero, insertando espacios entre ellos. Por ejemplo, "abc" se enviaría como "97 98 99". Esto podría ser preferible porque de alguna manera es más fácil de analizar cuando se depura, pero es difícil codificar/decodificar, especialmente si desea una verificación completa de errores al decodificar. –
¿Cuál es la motivación detrás de su segundo punto, solo que usa enteros sin signo? ¿Por qué no se pueden usar caracteres en la estructura (o matrices de caracteres) para enviar letras, bytes o cadenas? – aaronsnoswell