Structs
struct addrinfo
addrinfo
es una estructura utilizada en programación de sockets para almacenar información sobre direcciones de red y servidores. Esta estructura es útil cuando estás escribiendo código que necesita configurar sockets de red, como crear un servidor o un cliente, y deseas almacenar toda la información relevante en un solo lugar.
struct addrinfo {
int ai_flags; // Opciones para la búsqueda
int ai_family; // Familia de direcciones (IPv4 o IPv6 o AF_UNSPEC)
int ai_socktype; // Tipo de socket (SOCK_STREAM o SOCK_DGRAM)
int ai_protocol; // Protocolo utilizado (e.g., IPPROTO_TCP)
size_t ai_addrlen; // Longitud de la dirección
struct sockaddr *ai_addr; // Puntero a la dirección
char *ai_canonname; // Nombre canónico del host
struct addrinfo *ai_next; // Puntero al siguiente nodo en la lista
};
ai_flags
: Se utiliza para especificar opciones adicionales durante la resolución de direcciones mediantegetaddrinfo
.AI_PASSIVE
: Para usar con servidores, indica que la dirección IP del host local debe asignarse a las estructuras de socket.AI_CANONNAME
: Para obtener el nombre canónico del host.AI_NUMERICHOST
: Para evitar la resolución de nombres de dominio, si ya se tiene una dirección IP numérica.AI_NUMERICSERV
: Similar a AI_NUMERICHOST, pero para el número de puerto
ai_family
: Especifica la familia de direcciones, comoAF_INET
para IPv4 oAF_INET6
para IPv6.AF_UNSPEC
: No especifica IPv4 o IPv6, permitiendo cualquiera.AF_INET
: Para IPv4.AF_INET6
: Para IPv6.
ai_socktype
: Especifica el tipo de socket, comoSOCK_STREAM
para sockets TCP oSOCK_DGRAM
para sockets UDP.SOCK_STREAM
: Para sockets de flujo (TCP).SOCK_DGRAM
: Para sockets de datagramas (UDP).
ai_protocol
: Especifica el protocolo a utilizar, comoIPPROTO_TCP
para TCP oIPPROTO_UDP
para UDP.IPPROTO_TCP
: Para el protocolo TCP.IPPROTO_UDP
: Para el protocolo UDP.
ai_addr
: Un puntero a una estructurasockaddr
que contiene la información de dirección.ai_addrlen
: La longitud de la estructurasockaddr
.ai_canonname
: Un nombre canónico asociado con la dirección.ai_next
: Un puntero al siguiente elemento en la lista enlazada deaddrinfo
. Esto es útil cuandogetaddrinfo()
devuelve múltiples resultados.
Es posible que no necesites escribir en estas estructuras con frecuencia; en muchos casos, una llamada a getaddrinfo()
para completar tu struct addrinfo
será todo lo que necesites. Sin embargo, antes de realizar la llamada a getaddrinfo()
es recomendable vaciar completamente la estructura mediante memset()
.
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
getaddrinfo(NULL, PORT, &hints, &servinfo)

struct sockaddr
struct sockaddr
es una estructura que actúa como un tipo de dato genérico para representar direcciones de red en la programación de sockets en C. Puede adaptarse tanto a direcciones IPv4 como a direcciones IPv6, lo que la hace versátil y esencial en el desarrollo de aplicaciones de red.
La estructura
struct sockaddr
almacena información de dirección de socket para varios tipos de sockets.
struct sockaddr {
unsigned short sa_family; // Familia de direcciones, AF_xxx
char sa_data[14]; // Almacena la dirección (y otros datos en algunos casos)
};
sa_family
puede ser una variedad de cosas, pero en este documento será AF_INET
(IPv4) o AF_INET6
(IPv6) para todo lo que hacemos. sa_data
contiene una dirección de destino y un número de puerto para el socket. Esto puede ser un tanto engorroso ya que no deseas empaquetar manualmente la dirección en sa_data
.
struct sockaddr_in (IPv4)
Para lidiar con struct sockaddr
, los programadores crearon una estructura paralela: struct sockaddr_in
("in" de "Internet") para usar con IPv4.
Y aquí está la parte importante: un puntero a una struct sockaddr_in
se puede convertir en un puntero a una struct sockaddr
y viceversa. Entonces, incluso si connect()
requiere un struct sockaddr*
, todavía puedes usar una struct sockaddr_in
y convertirla en el último momento.
// Solo IPv4
struct sockaddr_in {
short int sin_family; // familia de direcciones, AF_INET
unsigned short int sin_port; // número de puerto
struct in_addr sin_addr; // dirección de Internet
unsigned char sin_zero[8]; // mismo tamaño que struct sockaddr
};
Esta estructura facilita la referencia a los elementos de la dirección del socket. Ten en cuenta que sin_zero
(que se incluye para rellenar la estructura al tamaño de una struct sockaddr
) debe configurarse con todos los ceros utilizando la función memset()
. Además, observa que sin_family
corresponde a sa_family
en una struct sockaddr
y debe configurarse como 'AF_INET'. Finalmente, el sin_port
debe estar en Network Byte Order (utilizando htons()
).
Observa que el campo sin_addr
es una estructura struct in_addr
. ¿Qué es eso? Bueno, sin dramatizar demasiado, es uno de los unions más impresionantes de todos los tiempos
// (IPv4 only--see struct in6_addr for IPv6)
// Internet address (a structure for historical reasons)
struct in_addr {
uint32_t s_addr; // that's a 32-bit int (4 bytes)
};
¡Vaya! Bueno, solía ser un union, pero parece que esos días han quedado atrás. Menos mal. Entonces, si has declarado 'ina' como del tipo struct sockaddr_in
, entonces 'ina.sin_addr.s_addr' hace referencia a la dirección IP de 4 bytes (en Network Byte Order). Ten en cuenta que incluso si tu sistema aún utiliza el unión espantoso para struct in_addr
, aún puedes hacer referencia a la dirección IP de 4 bytes de exactamente la misma manera que mencioné anteriormente (esto se debe a las definiciones con '#defines').
sockaddr_in6 (IPv6)
sockaddr_in6
es una estructura utilizada en programación de sockets para representar direcciones de red en el contexto de IPv6. A diferencia de la estructura sockaddr_in
, que se utiliza para direcciones IPv4, sockaddr_in6
está diseñada específicamente para IPv6.
// (IPv6 only--see struct sockaddr_in and struct in_addr for IPv4)
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
struct in6_addr {
unsigned char s6_addr[16]; // IPv6 address
};
Observa que IPv6 tiene una dirección IPv6 y un número de puerto, al igual que IPv4 tiene una dirección IPv4 y un número de puerto.
struct sockaddr_storage
struct sockaddr_storage
está diseñada para ser lo suficientemente grande como para contener tanto estructuras IPv4 como IPv6. Verás, en algunas llamadas, a veces no sabes de antemano si se completará tu struct sockaddr
con una dirección IPv4 o IPv6. Por lo tanto, pasas esta estructura paralela, muy similar a struct sockaddr
pero más grande, y luego la conviertes al tipo que necesitas.
struct sockaddr_storage {
sa_family_t ss_family; // address family
// all this is padding, implementation specific, ignore it:
char __ss_pad1[_SS_PAD1SIZE];
int64_t __ss_align;
char __ss_pad2[_SS_PAD2SIZE];
};
Lo importante es que puedes ver la familia de direcciones en el campo ss_family
. Verifícalo para ver si es AF_INET
o AF_INET6
(para IPv4 o IPv6). Luego puedes convertirlo en struct sockaddr_in
o struct sockaddr_in6
si así lo deseas.
Last updated