los unir() La función acepta un puntero a un sockaddr
pero en todos los ejemplos que he visto, un sockaddr_in
en su lugar se utiliza la estructura, y se moldea para sockaddr
:
struct sockaddr_in name;
...
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
...
No puedo entender por qué es un sockaddr_in
estructura utilizada. ¿Por qué no simplemente preparar y aprobar un sockaddr
?
¿Es solo convención?
No, no es solo una convención.
sockaddr
es un descriptor genérico para cualquier tipo de operación de socket, mientras que sockaddr_in
es una estructura específica para la comunicación basada en IP (IIRC, “in” significa “InterNet”). Hasta donde yo sé, se trata de una especie de “polimorfismo”: el bind()
función pretende tomar un struct sockaddr *
, pero de hecho, asumirá que se pasa el tipo apropiado de estructura; es decir, uno que corresponda al tipo de socket que le das como primer argumento.
No sé si es muy relevante para esta pregunta, pero me gustaría proporcionar información adicional que pueda hacer que el encasillado sea más comprensible para muchas personas que no han pasado mucho tiempo con C
confundirse al ver tal encasillamiento.
yo suelo macOS
por lo que estoy tomando ejemplos basados en archivos de encabezado de mi sistema.
struct sockaddr
se define de la siguiente manera:
struct sockaddr {
__uint8_t sa_len; /* total length */
sa_family_t sa_family; /* [XSI] address family */
char sa_data[14]; /* [XSI] addr value (actually larger) */
};
struct sockaddr_in
se define de la siguiente manera:
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
Comenzando desde lo básico, un puntero solo contiene una dirección. Entonces struct sockaddr *
y struct sockaddr_in *
son bastante iguales. Ambos solo almacenan una dirección. La única diferencia relevante es cómo el compilador trata sus objetos.
Así que cuando dices (struct sockaddr *) &name
solo está engañando al compilador y diciéndole que esta dirección apunta a un struct sockaddr
escribe.
Así que digamos que el puntero está apuntando a una ubicación 1000
. Si el struct sockaddr *
almacena esta dirección, considerará la memoria de 1000
para sizeof(struct sockaddr)
que poseen los miembros según la definición de la estructura. Si struct sockaddr_in *
almacena la misma dirección que considerará la memoria de 1000
para sizeof(struct sockaddr_in)
.
Cuando encasilló ese puntero, considerará la misma secuencia de bytes hasta sizeof(struct sockaddr)
.
struct sockaddr *a = &name; // consider &name = 1000
Ahora si accedo a->sa_len
el compilador accedería desde la ubicación 1000
para sizeof(__uint8_t)
que tiene el mismo tamaño de bytes que en el caso de sockaddr_in
. Entonces esto debería acceder a la misma secuencia de bytes.
El mismo patrón es para sa_family
.
Después de eso, hay una matriz de caracteres de 14 bytes en struct sockaddr
que almacena datos de in_port_t sin_port
(typedef
‘d entero sin signo de 16 bits = 2 bytes), struct in_addr sin_addr
(simplemente una dirección ipv4 de 32 bits = 4 bytes) y char sin_zero[8]
(8 bytes). Estos 3 se suman para hacer 14 bytes.
Ahora estos tres están almacenados en esta matriz de caracteres de 14 bytes y podemos acceder a cualquiera de estos tres accediendo a los índices apropiados y encasillándolos nuevamente.
La respuesta de user529758 ya explica la razón para hacer esto.
Esto se debe a que bind puede vincular otros tipos de sockets además de los sockets IP, por ejemplo, sockets de dominio Unix, que tienen sockaddr_un como su tipo. La dirección de un socket AF_INET tiene el host y el puerto como su dirección, mientras que un socket AF_UNIX tiene una ruta del sistema de archivos.
NÓTESE BIEN.
sockaddr_in6
también existe, y cualquier persona que escriba código nuevo debería incluirlo…– BRPocock
13/01/2014 a las 19:00
Ha omitido una parte muy importante en su código:
name.sa_family = AF_INET
porstruct sockaddr_in
! Considerarstruct sockaddr
ser una unión de todos los demás tipos de sockaddr. Lo único en común es que tienen un primer miembrosa_family_t sa_family
que debe corresponder al tipo de estructura real.–Ulrich Eckhardt
25 de enero de 2015 a las 10:47