Socket Addresses
A socket address pairs an IP address with a 16-bit transport port number (u16) to identify a specific communication endpoint on a host. Rust represents socket addresses with the enum SocketAddr (SocketAddr::V4(SocketAddrV4) and SocketAddr::V6(SocketAddrV6)).
SocketAddr::V4(SocketAddrV4)
+-- ip: Ipv4Addr (e.g., 127.0.0.1)
+-- port: u16 (e.g., 8080)
Text format: "127.0.0.1:8080"
SocketAddr::V6(SocketAddrV6)
+-- ip: Ipv6Addr (e.g., ::1)
+-- port: u16 (e.g., 8080)
+-- flowinfo: u32 (IPv6 traffic flow label, usually 0)
+-- scope_id: u32 (Link-local interface zone index, usually 0)
Text format: "[::1]:8080"
Constructing and Parsing Socket Addresses
Notice that when formatting or parsing an IPv6 socket address as a string, the IPv6 address must be enclosed in square brackets ([::1]:8080) to disambiguate the colons inside the IPv6 address from the :port separator.
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
fn main() {
// 1. Direct construction
let v4 = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 8080);
let v6 = SocketAddrV6::new(Ipv6Addr::LOCALHOST, 9090, 0, 0);
// 2. From (IpAddr, u16) or ([u8; 4], u16) tuples via From/Into
let from_tuple = SocketAddr::from(([192, 168, 0, 10], 5432));
let from_ip_pair = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 3000);
// 3. Parsing from string literals
let parsed_v4: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let parsed_v6: SocketAddr = "[2001:db8::1]:443".parse().unwrap();
assert_eq!(SocketAddr::V4(v4), parsed_v4);
println!("v4: {v4}");
println!("v6: {v6}");
println!("from_tuple: {from_tuple}");
println!("from_pair: {from_ip_pair}");
println!("parsed_v6: ip={}, port={}", parsed_v6.ip(), parsed_v6.port());
}
v4: 127.0.0.1:8080
v6: [::1]:9090
from_tuple: 192.168.0.10:5432
from_pair: 0.0.0.0:3000
parsed_v6: ip=2001:db8::1, port=443
Mutating IP and Port Fields In Place
SocketAddr, SocketAddrV4, and SocketAddrV6 provide .set_ip(...) and .set_port(...) methods for updating an endpoint without reconstructing the entire value:
use std::net::{Ipv4Addr, SocketAddr};
fn main() {
let mut addr: SocketAddr = "0.0.0.0:80".parse().unwrap();
println!("Initial: {addr}");
addr.set_ip(Ipv4Addr::LOCALHOST.into());
addr.set_port(8443);
println!("Updated: {addr}");
}
Initial: 0.0.0.0:80
Updated: 127.0.0.1:8443
Handling AddrParseError
Parsing a string via .parse::<SocketAddr>() performs syntactic parsing only—it never performs a DNS network lookup. Passing a hostname like "localhost:8080" to .parse::<SocketAddr>() returns Err(AddrParseError) (use ToSocketAddrs when DNS resolution is desired):
use std::net::SocketAddr;
fn main() {
let bad_inputs = [
"localhost:8080", // Hostname, not an IP literal
"::1:8080", // Missing brackets around IPv6 address
"127.0.0.1:99999", // Port exceeds u16::MAX (65535)
];
for input in bad_inputs {
let res = input.parse::<SocketAddr>();
println!("{input:<18} -> is_err: {}", res.is_err());
}
}
localhost:8080 -> is_err: true
::1:8080 -> is_err: true
127.0.0.1:99999 -> is_err: true