Infrastructure Go daemon
SECTION 9.2

UDP Basics

UDP is connectionless — send a packet, don't wait for acknowledgment.

Sending and Receiving

2 · Worked example — read every step
// Server: listen for packets
pc, err := net.ListenPacket("udp", ":5000")
if err != nil {
    log.Fatal(err)
}
defer pc.Close()

buf := make([]byte, 1024)
for {
    n, addr, err := pc.ReadFrom(buf)
    if err != nil {
        log.Println(err)
        continue
    }
    msg := string(buf[:n])
    slog.Info("received", "from", addr, "msg", msg)
    pc.WriteTo([]byte("ACK: "+msg), addr) // respond to sender
}
// Client: send a packet
conn, err := net.Dial("udp", "localhost:5000")
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

conn.Write([]byte("hello"))
buf := make([]byte, 1024)
n, _ := conn.Read(buf)
fmt.Println(string(buf[:n])) // "ACK: hello"

When to Use UDP

Use Case Why UDP
DNS queries Single request/response, low latency
Metrics (StatsD) Losing a metric is fine, speed matters
Service discovery Quick broadcast, no connection overhead
Game servers Latency > reliability
Health pings Simple, fast, stateless

TCP guarantees delivery and ordering. UDP doesn't — but it's faster and simpler for fire-and-forget patterns.

3 · Fill the gaps
A UDP metrics listener, from memory — the packet API, not the stream API.
pc, err := net.("udp", ":9125")
if err != nil {
    log.Fatal(err)
}
defer pc.Close()

buf := make([]byte, 1024) for { n, addr, err := pc.(buf) if err != nil { continue } metric := string() pc.([]byte("ok: "+metric), addr) }

4 · From scratch — this feeds your review queue