Socket addresses are represented differently in different languages and APIs. This module explains address structures and how to work with them.
Socket Address Formats
Python: Tuple Format
Python uses simple tuples for socket addresses:
# IPv4 address tuple: (host, port)
address = ('localhost', 8080)
address = ('192.168.1.100', 8080)
address = ('127.0.0.1', 3000)
# Usage
server.bind(('0.0.0.0', 8080))
client.connect(('example.com', 80))
Format: (host_string, port_integer)
- host: String (IP address or hostname)
- port: Integer (0-65535)
C: struct sockaddr
C uses structures for addresses:
#include <sys/socket.h>
#include <netinet/in.h>
// IPv4 address structure
struct sockaddr_in {
sa_family_t sin_family; // Address family (AF_INET)
in_port_t sin_port; // Port number
struct in_addr sin_addr; // IP address
char sin_zero[8]; // Padding
};
// Usage
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;
IPv6 Address Structure
struct sockaddr_in6 {
sa_family_t sin6_family; // AF_INET6
in_port_t sin6_port; // Port number
uint32_t sin6_flowinfo; // Flow information
struct in6_addr sin6_addr; // IPv6 address
uint32_t sin6_scope_id; // Scope ID
};
Converting Between Formats
String to IP Address
import socket
# Convert hostname to IP
ip = socket.gethostbyname('example.com')
# Returns: '93.184.216.34'
# Convert IP to hostname
hostname = socket.gethostbyaddr('93.184.216.34')
# Returns: ('example.com', [], ['93.184.216.34'])
# Get all IPs for a hostname
ips = socket.gethostbyname_ex('example.com')
# Returns: ('example.com', [], ['93.184.216.34'])
IP Address to Integer
import socket
import struct
# IPv4 string to integer
ip_str = '192.168.1.1'
ip_int = struct.unpack('!I', socket.inet_aton(ip_str))[0]
# Returns: 3232235777
# Integer to IPv4 string
ip_str = socket.inet_ntoa(struct.pack('!I', ip_int))
# Returns: '192.168.1.1'
# IPv6 (Python 3.4+)
ip_str = '2001:db8::1'
ip_bytes = socket.inet_pton(socket.AF_INET6, ip_str)
ip_str = socket.inet_ntop(socket.AF_INET6, ip_bytes)
Special Addresses
INADDR_ANY / 0.0.0.0
Meaning: Bind to all available interfaces
# Python
server.bind(('0.0.0.0', 8080)) # All interfaces
server.bind(('', 8080)) # Same as above
# C
server_addr.sin_addr.s_addr = INADDR_ANY;
Use case: Server accepting connections on any network interface
127.0.0.1 / localhost
Meaning: Loopback interface (local machine only)
# Python
server.bind(('127.0.0.1', 8080)) # Localhost only
server.bind(('localhost', 8080)) # Same (usually)
# Only accessible from same machine
Use case: Local testing, local services
255.255.255.255
Meaning: Broadcast address (IPv4)
# UDP broadcast
client.sendto(data, ('255.255.255.255', 8080))
Use case: Broadcast messages to all devices on network
Getting Socket Address Information
Get Local Address
# Get address this socket is bound to
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0', 8080))
addr = sock.getsockname()
# Returns: ('0.0.0.0', 8080)
# Get actual bound address after binding
sock.bind(('', 0)) # Bind to any port
addr = sock.getsockname()
# Returns: ('0.0.0.0', <assigned_port>)
Get Peer Address
# Get address of connected peer (client side)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('example.com', 80))
server_addr = client.getpeername()
# Returns: ('93.184.216.34', 80)
# On server side (after accept)
client_sock, client_addr = server.accept()
# client_addr is already provided
# Or use: client_sock.getpeername()
Get All Interface Addresses
import socket
# Get all IP addresses of this machine
hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
# Get all IPs (including loopback, etc.)
for interface in socket.getaddrinfo(hostname, None):
print(interface[4][0]) # IP address
# Using netifaces (if installed)
try:
import netifaces
for interface in netifaces.interfaces():
addrs = netifaces.ifaddresses(interface)
if netifaces.AF_INET in addrs:
for addr in addrs[netifaces.AF_INET]:
print(addr['addr'])
except ImportError:
pass
Address Resolution: getaddrinfo()
The getaddrinfo() function is the modern way to resolve addresses:
import socket
# Resolve hostname and port
info = socket.getaddrinfo(
'example.com', # hostname
80, # port
socket.AF_INET, # address family (or AF_UNSPEC for both)
socket.SOCK_STREAM # socket type
)
# Returns list of tuples:
# (family, type, proto, canonname, sockaddr)
# Example: [(2, 1, 6, '', ('93.184.216.34', 80))]
# Use first result
family, socktype, proto, canonname, sockaddr = info[0]
sock = socket.socket(family, socktype)
sock.connect(sockaddr)
Benefits of getaddrinfo()
- Supports both IPv4 and IPv6
- Returns all matching addresses
- Works with hostnames and IPs
- Recommended for modern code
Working with IPv6
IPv6 Address Format
# IPv6 address tuple (Python)
address = ('::1', 8080) # IPv6 localhost
address = ('2001:db8::1', 8080)
# Creating IPv6 socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind(('::', 8080)) # All IPv6 interfaces
Dual-Stack Sockets (IPv4 + IPv6)
# Create socket that accepts both IPv4 and IPv6
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
sock.bind(('::', 8080))
# Now accepts both IPv4 and IPv6 connections
Port Numbers
Well-Known Ports (0-1023)
# Reserved for system services
HTTP_PORT = 80
HTTPS_PORT = 443
SSH_PORT = 22
SMTP_PORT = 25
DNS_PORT = 53
# Need root/admin privileges to bind
Registered Ports (1024-49151)
# For registered applications
MYSQL_PORT = 3306
POSTGRES_PORT = 5432
REDIS_PORT = 6379
MONGO_PORT = 27017
Dynamic/Private Ports (49152-65535)
# For client-side ephemeral ports
# OS assigns automatically for outgoing connections
Getting Available Port
import socket
def get_free_port():
"""Get a free port number."""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', 0)) # Bind to any available port
port = sock.getsockname()[1]
sock.close()
return port
# Usage
port = get_free_port()
print(f"Free port: {port}")
Address Comparison
# Compare addresses
addr1 = ('192.168.1.1', 8080)
addr2 = ('192.168.1.1', 8080)
if addr1 == addr2:
print("Same address")
# Compare IPs (ignore port)
if addr1[0] == addr2[0]:
print("Same IP")
Common Patterns
Bind to All Interfaces
server.bind(('0.0.0.0', 8080)) # IPv4
# or
server.bind(('', 8080)) # Shorter
Bind to Localhost Only
server.bind(('127.0.0.1', 8080)) # IPv4 localhost
server.bind(('localhost', 8080)) # Usually same
Connect with Hostname Resolution
# Automatically resolves hostname
client.connect(('example.com', 80))
# Or resolve first
ip = socket.gethostbyname('example.com')
client.connect((ip, 80))
Key Takeaway: Socket addresses are represented as (host, port) tuples in Python. Use getaddrinfo() for modern address resolution, and understand special addresses like 0.0.0.0 (all interfaces) and 127.0.0.1 (localhost).