Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

UDP

Send and receive a UDP datagram

std-badge cat-net-badge

UDP is connectionless: the sender fires a packet at an address and the receiver picks it up if it arrives. There is no session, no handshake, no retransmit. Statsd, syslog, NTP, and DNS all run on UDP for the same reason — minimum overhead when delivery guarantees aren’t worth the cost.

This example wires both ends together so it runs as a single program. The collector binds to an OS-allocated port and waits with recv_from. The client binds to its own ephemeral port and uses send_to to deliver a metric. recv_from returns the byte count and the sender’s address.

use std::io;
use std::net::UdpSocket;

fn main() -> io::Result<()> {
    let collector = UdpSocket::bind("127.0.0.1:0")?;
    let collector_addr = collector.local_addr()?;

    let client = UdpSocket::bind("127.0.0.1:0")?;
    client.send_to(b"app.requests:1|c", collector_addr)?;

    let mut buf = [0u8; 1500];
    let (n, from) = collector.recv_from(&mut buf)?;
    let metric = std::str::from_utf8(&buf[..n]).unwrap_or("<binary>");
    println!("received {n} bytes from {from}: {metric}");
    Ok(())
}

Join a UDP multicast group

std-badge cat-net-badge

Multicast lets one sender reach many receivers without addressing each one individually. Service discovery (mDNS, SSDP) and announcement protocols rely on it. A receiver binds to the multicast port and joins a group with join_multicast_v4; the OS then delivers any datagram sent to that group to every receiver that joined.

Multicast group addresses live in 224.0.0.0/4. Anything from 239.0.0.0 to 239.255.255.255 is reserved for private use — pick from there for in-house apps.

use std::io;
use std::net::{Ipv4Addr, SocketAddr, UdpSocket};

fn main() -> io::Result<()> {
    let group = Ipv4Addr::new(239, 0, 0, 100);
    let port = 7878;

    // Receiver: bind to the port, then join the group on every interface.
    let receiver = UdpSocket::bind(SocketAddr::from(([0, 0, 0, 0], port)))?;
    receiver.join_multicast_v4(&group, &Ipv4Addr::UNSPECIFIED)?;

    // Sender: any local socket can send to the group address.
    let sender = UdpSocket::bind("0.0.0.0:0")?;
    sender.send_to(b"hello group", SocketAddr::new(group.into(), port))?;

    let mut buf = [0u8; 64];
    let (n, from) = receiver.recv_from(&mut buf)?;
    println!("got {n} bytes from {from}");
    Ok(())
}