Mastering UDP in Go: Build Low‑Latency Network Apps with Simple Code
This article explains the characteristics and ideal use cases of UDP, then walks through step‑by‑step Go code for creating UDP connections, sending and receiving datagrams, and a complete client‑server example, helping developers leverage UDP’s low latency and lightweight nature for real‑time communication, streaming, and IoT scenarios.
Introduction
In network programming, UDP (User Datagram Protocol) is a connectionless protocol that provides low latency because it has no connection‑establishment or teardown phases. It does not guarantee reliability or ordering, making it suitable for real‑time and lightweight communication.
Typical UDP Application Scenarios and Advantages
Real‑time Communication
Voice and video calls require continuous, low‑latency streams; occasional packet loss is acceptable. Online games need rapid position updates and action synchronization, where UDP’s stateless delivery reduces delay.
Broadcast and Multicast
UDP supports broadcast and multicast, allowing a single packet to reach many receivers on a LAN. This is useful for video streams, status updates, and IoT devices that need to distribute data to multiple nodes.
Simple Query/Response
DNS lookups and NTP use small request‑response messages where latency is critical. UDP’s stateless nature enables fast processing of these queries.
Streaming Media
Video streaming and live data feeds (e.g., stock quotes, sports scores) benefit from a steady flow of packets without the overhead of TCP’s retransmission mechanisms.
Lightweight Communication
Resource‑constrained sensors and lightweight application‑layer protocols such as TFTP use UDP to minimise header overhead and conserve bandwidth.
Key Advantages of UDP
Low latency : No connection handshake reduces round‑trip time.
Broadcast/Multicast : One packet can be delivered to multiple endpoints.
Small header : Reduces per‑packet overhead, ideal for constrained devices.
Flexibility : Applications can implement custom reliability or ordering logic.
Basic UDP Programming in Go
Go’s net package provides the UDPConn type. A typical workflow consists of three steps:
Create a UDP connection (client) with net.DialUDP or a listening socket (server) with net.ListenUDP.
Send and receive datagrams using Write, WriteToUDP, Read or ReadFromUDP.
Close the connection with Close (usually deferred).
Creating a UDP Connection
Resolve the remote address with net.ResolveUDPAddr and then call net.DialUDP:
package main
import (
"fmt"
"net"
)
func main() {
addr, err := net.ResolveUDPAddr("udp", "localhost:8080")
if err != nil {
fmt.Println("Error resolving address:", err)
return
}
conn, err := net.DialUDP("udp", nil, addr)
if err != nil {
fmt.Println("Error dialing:", err)
return
}
defer conn.Close()
fmt.Println("UDP connection established")
}Sending Data
Use Write (or WriteToUDP) to transmit a byte slice. The example below sends a simple greeting to a server:
package main
import (
"fmt"
"net"
"os"
)
func main() {
addr, err := net.ResolveUDPAddr("udp", "localhost:8080")
if err != nil {
fmt.Println("Error resolving address:", err)
return
}
conn, err := net.DialUDP("udp", nil, addr)
if err != nil {
fmt.Println("Error dialing:", err)
return
}
defer conn.Close()
message := []byte("Hello, UDP Server!")
if _, err = conn.Write(message); err != nil {
fmt.Println("Error writing to UDP server:", err)
os.Exit(1)
}
fmt.Println("Message sent to UDP server")
}Receiving Data
On the server side, call net.ListenUDP to obtain a listening socket and read incoming packets with ReadFromUDP. The server below echoes a confirmation back to the client:
package main
import (
"fmt"
"net"
)
func main() {
addr, err := net.ResolveUDPAddr("udp", ":8080")
if err != nil {
fmt.Println("Error resolving address:", err)
return
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
fmt.Println("Error listening:", err)
return
}
defer conn.Close()
buffer := make([]byte, 1024)
for {
n, clientAddr, err := conn.ReadFromUDP(buffer)
if err != nil {
fmt.Println("Error reading from UDP client:", err)
continue
}
fmt.Printf("Received message from %s: %s
", clientAddr, string(buffer[:n]))
response := []byte("Message received")
if _, err = conn.WriteToUDP(response, clientAddr); err != nil {
fmt.Println("Error sending response:", err)
}
}
}Complete Example
Save the server code as server.go and the client code (the sending example) as client.go. Run them in separate terminals:
go run server.go
# in another terminal
go run client.goTypical output demonstrates a full round‑trip:
Received message from 127.0.0.1:65174: Hello, UDP Server!
Received response from server: Message receivedConclusion
Go’s net package makes UDP communication concise: resolve addresses, create a UDPConn, exchange datagrams, and close the socket. This pattern is well‑suited for low‑latency, real‑time, or lightweight protocols such as DNS, NTP, video streaming, and IoT telemetry.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ops Development & AI Practice
DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
