sockaddr_in - Pasar una estructura a través de Sockets en C
funcion socket() (7)
En lugar de serializar y depender de bibliotecas de terceros, es fácil crear un protocolo primitivo que use etiqueta, longitud y valor.
Tag: 32 bit value identifying the field
Length: 32 bit value specifying the length in bytes of the field
Value: the field
Concatenar según sea necesario. Use enumeraciones para las etiquetas. Y use el orden de bytes de red ...
Fácil de codificar, fácil de decodificar.
Además, si usa TCP, recuerde que es una secuencia de datos, por lo que si envía, por ejemplo, 3 paquetes, no necesariamente recibirá 3 paquetes. Pueden estar "fusionados" en una secuencia dependiendo del algoritmo nodelay / nagel, entre otras cosas, y puede obtenerlos todos en una sola rec ... Debe delimitar los datos, por ejemplo, usando RFC1006.
UDP es más fácil, recibirá un paquete distinto para cada paquete enviado, pero es mucho menos seguro.
Estoy tratando de pasar toda la estructura de cliente a servidor o viceversa. Supongamos nuestra estructura de la siguiente manera
struct temp {
int a;
char b;
}
Estoy usando sendto y enviando la dirección de la variable de estructura y recibiéndola en el otro lado usando la función recvfrom . Pero no puedo obtener los datos originales enviados en el extremo receptor. En la función sendto guardo los datos recibidos en la variable de tipo struct temp.
n = sendto(sock, &pkt, sizeof(struct temp), 0, &server, length);
n = recvfrom(sock, &pkt, sizeof(struct temp), 0, (struct sockaddr *)&from,&fromlen);
Donde pkt es la variable de tipo struct temp.
A pesar de que estoy recibiendo 8 bytes de datos, pero si intento imprimir, simplemente muestra los valores de basura. ¿Alguna ayuda para solucionarlo?
NOTA: No se deben usar Bibliotecas de terceros.
EDIT1: Soy realmente nuevo en este concepto de serialización. Pero sin hacer serialización, ¿no puedo enviar una estructura a través de sockets?
EDIT2: Cuando trato de enviar una cadena o una variable entera usando las funciones sendto y recvfrom , recibo los datos correctamente en el receptor. ¿Por qué no en el caso de una estructura? Si no tengo que usar la función de serialización, ¿debería enviar a cada miembro de la estructura individualmente? Realmente no es una solución adecuada, ya que si hay un número n de miembros, entonces se agregarán ''n'' líneas de código solo para enviar o recibir datos.
Esta es una muy mala idea. Los datos binarios siempre se deben enviar de una manera que:
- Maneja diferente endianness
- Maneja diferente padding
- Maneja las diferencias en los tamaños de bytes de los tipos intrínsecos
Nunca escriba una estructura completa de forma binaria, ni en un archivo, ni en un socket.
Siempre escriba cada campo por separado y léelos de la misma manera.
Necesita tener funciones como
unsigned char * serialize_int(unsigned char *buffer, int value)
{
/* Write big-endian int value into buffer; assumes 32-bit int and 8-bit char. */
buffer[0] = value >> 24;
buffer[1] = value >> 16;
buffer[2] = value >> 8;
buffer[3] = value;
return buffer + 4;
}
unsigned char * serialize_char(unsigned char *buffer, char value)
{
buffer[0] = value;
return buffer + 1;
}
unsigned char * serialize_temp(unsigned char *buffer, struct temp *value)
{
buffer = serialize_int(buffer, value->a);
buffer = serialize_char(buffer, value->b);
return buffer;
}
unsigned char * deserialize_int(unsigned char *buffer, int *value);
O el equivalente, hay, por supuesto, varias formas de configurar esto en lo que respecta a la gestión de búferes, etc. Luego debe realizar las funciones de nivel superior que serializan / deserializan estructuras completas.
Esto supone que la serialización se realiza desde / hacia los búferes, lo que significa que la serialización no necesita saber si el destino final es un archivo o un socket. También significa que usted paga un poco de sobrecarga de memoria, pero generalmente es un buen diseño por razones de rendimiento (no desea hacer una escritura () de cada valor en el socket).
Una vez que tenga lo anterior, aquí le mostramos cómo puede serializar y transmitir una instancia de estructura:
int send_temp(int socket, const struct sockaddr *dest, socklen_t dlen,
const struct temp *temp)
{
unsigned char buffer[32], *ptr;
ptr = serialize_temp(buffer, temp);
return sendto(socket, buffer, ptr - buffer, 0, dest, dlen) == ptr - buffer;
}
Algunos puntos para tener en cuenta sobre lo anterior:
- La estructura para enviar se serializa primero, campo por campo, en el
buffer
. - La rutina de serialización devuelve un puntero al siguiente byte libre en el búfer, que usamos para calcular cuántos bytes serializó
- Obviamente, mis rutinas de serialización de ejemplo no protegen contra el desbordamiento del búfer.
- El valor
sendto()
es 1 si la llamada asendto()
tuvo éxito, de lo contrario será 0.
La serialización es una buena idea. También puede usar "wireshark" para controlar el tráfico y comprender qué se pasa realmente en los paquetes.
No es necesario escribir sus propias rutinas de serialización para tipos enteros short
y long
; use las funciones POSIX de htons()
/ htonl()
.
Si el formato de los datos que desea transferir es muy simple, la conversión ay desde una cadena ANSI es simple y portátil.
Si no desea escribir el código de serialización usted mismo, busque un marco de serialización adecuado y úselo.
¿Tal vez los búferes de protocolo de Google serían posibles?
Usar la opción del paquete ''pragma'' resolvió mi problema, pero no estoy seguro si tiene alguna dependencia ??
#pragma pack(1) // this helps to pack the struct to 5-bytes
struct packet {
int i;
char j;
};
#pragma pack(0) // turn packing off
Entonces las siguientes líneas de código funcionó bien sin ningún problema
n = sendto(sock,&pkt,sizeof(struct packet),0,&server,length);
n = recvfrom(sock, &pkt, sizeof(struct packet), 0, (struct sockaddr *)&from, &fromlen);