UDP Echo Server and Client with Deadlines
Simple UDP echo pair showing packet send and receive with deadlines and graceful shutdown loops.
main.go
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
package main
import (
"context"
"fmt"
"log"
"net"
"time"
)
func runUDPEchoServer(ctx context.Context, addr string) (*net.UDPConn, error) {
udpAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return nil, err
}
conn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
return nil, err
}
go func() {
defer conn.Close()
buf := make([]byte, 2048)
for {
select {
case <-ctx.Done():
return
default:
}
_ = conn.SetReadDeadline(time.Now().Add(1 * time.Second))
n, peer, err := conn.ReadFromUDP(buf)
if err != nil {
if ne, ok := err.(net.Error); ok && ne.Timeout() {
continue
}
return
}
_ = conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
conn.WriteToUDP(buf[:n], peer)
}
}()
return conn, nil
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
server, err := runUDPEchoServer(ctx, "127.0.0.1:0")
if err != nil {
log.Fatalf("server: %v", err)
}
serverAddr := server.LocalAddr().String()
log.Printf("udp echo server on %s", serverAddr)
client, err := net.Dial("udp", serverAddr)
if err != nil {
log.Fatalf("dial: %v", err)
}
defer client.Close()
msg := []byte("hello udp")
client.SetWriteDeadline(time.Now().Add(1 * time.Second))
if _, err := client.Write(msg); err != nil {
log.Fatalf("write: %v", err)
}
buf := make([]byte, 2048)
client.SetReadDeadline(time.Now().Add(1 * time.Second))
n, err := client.Read(buf)
if err != nil {
log.Fatalf("read: %v", err)
}
fmt.Println(string(buf[:n]))
}How It Works
Simple UDP echo pair showing packet send and receive with deadlines and graceful shutdown loops.
Server listens on UDP, reads datagrams with a read deadline, echoes payloads back, and exits on context cancel; client dials UDP, sends messages, reads responses with per-operation timeouts, then closes sockets.
Key Concepts
- 1Per-operation deadlines keep both server and client from blocking indefinitely.
- 2Loop handles network errors and context cancellation gracefully.
- 3Demonstrates basic UDP read and write semantics without connections.
When to Use This Pattern
- Baseline for custom UDP protocols or game servers.
- Network troubleshooting tools.
- Education on datagram versus stream socket behavior.
Best Practices
- Size buffers to expected packet sizes and handle truncation.
- Validate source addresses if echoing to avoid amplification issues.
- Shut down listeners on context cancel to free the port quickly.
Go Version1.18+
Difficultybeginner
Production ReadyYes
Lines of Code77