IPv4 socket Address structure
This structure, named sockaddr_in, is the one you will use most often for standard Internet programming. It is defined in the <netinet/in.h> header.
struct in_addr {
in_addr_t s_addr; /* 32-bit IPv4 address */
/* network byte ordered */
};
struct sockaddr_in {
uint8_t sin_len; /* length of structure (16) */
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port; /* 16-bit TCP or UDP port number */
/* network byte ordered */
struct in_addr sin_addr; /* 32-bit IPv4 address */
/* network byte ordered */
char sin_zero[8]; /* unused */
};sin_family: Always set toAF_INETfor IPv4.sin_port: The 16-bit port number (e.g., 80 for Web). Important: This must be stored in network byte order (Big Endian).sin_addr: The 32-bit IPv4 address. This is also stored in network byte order. The address is actually stored inside a smaller structure calledin_addr, which contains just one field:s_addr. So, to access the address, you typeserv.sin_addr.s_addr.sin_zero: An unused 8-byte field. We always fill this with zeros (usually by clearing the whole structure withbzeroormemsetfirst). Its purpose is to make the structure exactly 16 bytes long, which was a requirement for older protocols.
The Generic Socket Address Structure
Socket functions (like bind and connect) need to work with any protocol (IPv4, IPv6, Unix Domain, etc.). However, C did not have a “generic” pointer type (like void *) when these functions were originally written. To solve this, the designers created a generic structure: struct sockaddr.
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family; /* address family: AF_xxx value */
char sa_data[14]; /* protocol-specific address */
};Note
Whenever you call a socket function, you must cast your specific pointer (like
struct sockaddr_in *) to a generic pointer (struct sockaddr *).
The IPv6 Socket Address Structure
For the modern Internet protocol (IPv6), we use sockaddr_in6, defined in <netinet/in.h>
struct in6_addr {
uint8_t s6_addr[16]; /* 128-bit IPv6 address */
};
#define SIN6_LEN /* required for compile-time tests */
struct sockaddr_in6 {
uint8_t sin6_len; /* length of this struct (28) */
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* transport layer port# */
uint32_t sin6_flowinfo; /* flow information, undefined */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* set of interfaces for a scope */
};- It is larger (28 bytes) to accommodate the massive 128-bit IPv6 address.
sin6_family: Always set toAF_INET6.sin6_addr: The 128-bit IPv6 address.sin6_flowinfo: Used for traffic class and flow labeling (advanced QoS features).sin6_scope_id: Used for scoped addresses (like link-local addresses), identifying which network interface the address belongs to.
New Generic Socket Address Structure
- Unlike the old
struct sockaddr, this structure is large enough to hold any socket address supported by the system (IPv4, IPv6, or others). - This is useful when you don’t know what kind of address you’ll receive (e.g., writing a server that handles both IPv4 and IPv6). You can declare a variable of this type, receive the address into it, and then check the
ss_familyfield to cast it to the correct type later.