Socket Addressing

Socket addressing involves defining the endpoint for network communication. This includes specifying the network protocol, the local and remote machine addresses, and the port numbers used by applications.

The SOCKADDR Structure

The generic SOCKADDR structure is a foundation for socket address structures. However, you will typically use more specific structures like SOCKADDR_IN for IPv4 or SOCKADDR_IN6 for IPv6.


typedef struct sockaddr {
    u_short sa_family;
    char    sa_data[14];
} SOCKADDR;
                
  • sa_family: Specifies the address family. For IPv4, this is AF_INET; for IPv6, it's AF_INET6.
  • sa_data: Contains the socket address. This field is a union in specific address structures.

IPv4 Socket Addressing (SOCKADDR_IN)

For IPv4 communication, the SOCKADDR_IN structure is used. It contains the address family, port number, and IP address.


typedef struct sockaddr_in {
    short int          sin_family;
    u_short            sin_port;
    struct in_addr     sin_addr;
    char               sin_zero[8];
} SOCKADDR_IN;
                
  • sin_family: Must be AF_INET.
  • sin_port: The port number, in network byte order.
  • sin_addr: A structure containing the IPv4 address.
  • sin_zero: Reserved and must be zero.

The in_addr Structure

The in_addr structure holds the 32-bit IPv4 address.


struct in_addr {
    union {
        struct {
            u_char s_b1, s_b2, s_b3, s_b4;
        } S_un_b;
        u_short S_un_w[2];
        u_long  S_addr;
    } S_un;
};
                

The most common way to access the address is through S_un.S_addr, which stores the address as a 32-bit unsigned integer in network byte order.

IPv6 Socket Addressing (SOCKADDR_IN6)

For IPv6 communication, the SOCKADDR_IN6 structure is used.


typedef struct sockaddr_in6 {
    short int       sin6_family;
    u_short         sin6_port;
    u_long          sin6_flowinfo;
    struct in6_addr sin6_addr;
    u_long          sin6_scope_id;
} SOCKADDR_IN6;
                
  • sin6_family: Must be AF_INET6.
  • sin6_port: The port number, in network byte order.
  • sin6_flowinfo: Flow information for the IPv6 header.
  • sin6_addr: A structure containing the IPv6 address.
  • sin6_scope_id: Scope identifier for link-local addresses.

The in6_addr Structure

The in6_addr structure holds the 128-bit IPv6 address.


struct in6_addr {
    union {
        u_char Byte[16];
        u_short Word[8];
    } u;
};
                

Byte Order Conversion

Port numbers and IP addresses stored in socket address structures are in network byte order (big-endian). Host systems may use a different byte order (little-endian). You must use conversion functions to ensure correct interpretation.

  • htons(): Host to network short (for port numbers).
  • ntohs(): Network to host short (for port numbers).
  • htonl(): Host to network long (for IPv4 addresses).
  • ntohl(): Network to host long (for IPv4 addresses).
Important: Always ensure that port numbers and IP addresses are converted to network byte order before being placed into socket address structures and sent over the network.

Resolving Hostnames

Applications often need to resolve hostnames (e.g., "www.example.com") to IP addresses. The Winsock API provides functions for this purpose:

  • gethostbyname(): Resolves a hostname to an IPv4 address. Deprecated in favor of getaddrinfo.
  • getaddrinfo(): A more modern and versatile function for resolving both IPv4 and IPv6 addresses, handling various hints and service names.
Best Practice: Use getaddrinfo() for new development as it supports both IPv4 and IPv6, and offers more flexibility in specifying connection preferences.

Example: Populating an IPv4 Socket Address


#include <winsock2.h>
#include <ws2tcpip.h>

// ...

SOCKADDR_IN serverAddr;
int port = 80; // Example port

ZeroMemory(&serverAddr, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port); // Convert port to network byte order

// Convert IP address string to network byte order
// For example, to connect to localhost (127.0.0.1)
if (inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr) <= 0) {
    // Handle error
}

// For listening on all interfaces, use INADDR_ANY
// serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
                

Related Topics