Networking with the Standard Library

Networking Fundamentals

Network programming enables processes running on the same machine or across different hosts to exchange data over standardized communication protocols. Operating systems expose network communication through sockets—endpoints identified by an IP address, a transport protocol, and a 16-bit port number.

+-------------------------------------------------------------------+
| Application Layer      HTTP, DNS, Redis, Custom Framing (App Code)|
+-------------------------------------------------------------------+
| Transport Layer        TCP (Byte Stream)   |   UDP (Datagrams)    |
|                        (std::net::Tcp*)    |   (std::net::Udp*)   |
+-------------------------------------------------------------------+
| Network Layer          IPv4 (32-bit)       |   IPv6 (128-bit)     |
|                        (Ipv4Addr)          |   (Ipv6Addr)         |
+-------------------------------------------------------------------+
| Link / Hardware Layer  Ethernet, Wi-Fi, Loopback (OS Kernel)      |
+-------------------------------------------------------------------+

Transport Protocols: TCP vs UDP

The Rust standard library (std::net) provides direct abstractions over the two primary transport-layer protocols: Transmission Control Protocol (TCP) and User Datagram Protocol (UDP).

Characteristic TCP (TcpStream, TcpListener) UDP (UdpSocket)
Connection Model Connection-oriented (3-way handshake before data transfer) Connectionless (send packets immediately to any address)
Abstraction Continuous, unstructured byte stream (Read + Write) Discrete, message-bounded datagrams (send_to / recv_from)
Reliability Guaranteed delivery; automatic retransmission of lost packets Unreliable; packets may be dropped without notification
Ordering Strictly ordered; bytes arrive in the exact sequence sent Unordered; datagrams may arrive out of order or duplicated
Flow & Congestion Control Built-in kernel flow window and congestion control None (application must pace itself)
Typical Use Cases HTTP/HTTPS, databases, SSH, RPC, file transfer DNS queries, real-time voice/video, gaming telemetry, service discovery

IP Addresses, Ports, and Loopback

Every transport socket binds or connects to a socket address (IP Address + Port):

  • IP Address: Identifies the host interface on the network (e.g., 192.0.2.10 in IPv4 or 2001:db8::1 in IPv6).
  • Port (u16): A 16-bit unsigned integer (0..=65535) that multiplexes traffic to a specific process on that host.
    • 0: Reserved as a wildcard port when binding; instructs the OS kernel to assign an unused ephemeral port automatically.
    • 1..=1023: Well-known / privileged ports (such as 80 for HTTP, 443 for HTTPS, 53 for DNS).
    • 1024..=49151: Registered application ports (such as 5432 for PostgreSQL, 6379 for Redis).
    • 49152..=65535: Dynamic / ephemeral ports used for short-lived client connections.
  • Loopback (127.0.0.1 / ::1): A virtual network interface routed entirely inside the local OS kernel without touching physical network hardware.

Ephemeral Port Assignment on Loopback

Binding a listener or socket to "127.0.0.1:0" asks the kernel to pick a free port immediately, which can then be inspected via .local_addr() for local client-server tests:

use std::io;
use std::net::TcpListener;

fn main() -> io::Result<()> {
    // Port 0 requests an OS-assigned ephemeral port on the IPv4 loopback interface
    let listener = TcpListener::bind("127.0.0.1:0")?;
    let bound_addr = listener.local_addr()?;

    println!("Bound IP:   {}", bound_addr.ip());
    println!("Assigned non-zero port: {}", bound_addr.port() > 0);
    Ok(())
}
Bound IP:   127.0.0.1
Assigned non-zero port: true