UDP服务端用net.ListenUDP监听并循环调用ReadFromUDP读取数据,必须指定含端口的地址(如":8080"),返回字节数和客户端地址用于回包,缓冲区建议至少1500字节。

UDP服务端怎么监听并读取数据
Go 的 net.ListenUDP 是启动 UDP 服务端的唯一入口,它返回一个 *UDPConn,后续所有收发都基于它。注意:UDP 是无连接的,所以服务端不需要“接受连接”,而是直接在绑定地址上循环 ReadFromUDP。
常见错误是用 net.Listen(它只支持 TCP/Unix),或忘记设置地址中的端口(如写成 "localhost:" 而非 "localhost:8080")。
- 监听地址必须包含端口号,推荐用
":8080"表示监听本机所有 IPv4/IPv6 地址 -
ReadFromUDP返回实际接收字节数和对端地址,这个地址要原样用于后续回复 - 缓冲区建议至少 1500 字节(以适配典型 MTU),太小会导致截断且不报错
conn, _ := net.ListenUDP("udp", &net.UDPAddr{Port: 8080})
defer conn.Close()
buf := make([]byte, 1500)
for {
n, addr, _ := conn.ReadFromUDP(buf)
fmt.Printf("收到 %d 字节 from %v: %s\n", n, addr, string(buf[:n]))
}UDP客户端怎么发送并接收响应
客户端用 net.DialUDP 或直接用 &net.UDPAddr{} + WriteToUDP 都可以。前者会预设远端地址,后续调用 Write 就自动发给该地址;后者更灵活,每次都能指定不同目标。
容易被忽略的是:UDP 没有“连接成功”概念,DialUDP 即使目标地址不可达也不会失败,只有真正 Write 或 Read 时才可能出错(比如 ICMP 目标不可达被内核返回)。
立即学习“go语言免费学习笔记(深入)”;
- 如果只发不收,用
WriteToUDP更轻量,无需维护连接状态 - 若需收响应,务必用同一个
*UDPConn调用ReadFromUDP,且缓冲区足够大 - 客户端绑定本地端口可设为
0(让系统自动分配),避免端口冲突
conn, _ := net.DialUDP("udp", &net.UDPAddr{Port: 0}, &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8080})
conn.Write([]byte("hello"))
buf := make([]byte, 1500)
n, _, _ := conn.ReadFromUDP(buf)
fmt.Printf("收到响应: %s\n", string(buf[:n]))如何处理并发与超时
UDP 本身无连接、无序、不可靠,但 Go 的 *UDPConn 是线程安全的,多个 goroutine 可同时调用 ReadFromUDP 和 WriteToUDP —— 这意味着你不用手动加锁,但得自己管理每个请求-响应的匹配逻辑。
真正的难点在于:没有内置超时机制。如果对方不回包,ReadFromUDP 会永久阻塞。必须用 SetReadDeadline 或 SetDeadline 控制。
-
SetReadDeadline接收time.Time,常用time.Now().Add(3 * time.Second) - 超时后
ReadFromUDP返回io.EOF或net.ErrDeadlineExceeded,需显式检查 - 不要在循环中重复调用
SetReadDeadline而不重置,否则第二次读会立即超时
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
n, addr, err := conn.ReadFromUDP(buf)
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
fmt.Println("读取超时")
}
return
}为什么收不到包?几个关键排查点
UDP 通信失败绝大多数不是代码问题,而是环境或配置层面的“静默丢包”。最常踩的坑是防火墙、NAT、地址绑定和缓冲区溢出。
- 服务端用
"localhost:8080"绑定,客户端却连"127.0.0.1:8080"—— 看似一样,但某些系统下localhost解析为 IPv6 ::1,而127.0.0.1是 IPv4,协议不匹配就收不到 - Windows/macOS 自带防火墙默认拦截 UDP 入站,服务端跑起来没报错,但包根本进不来
- 服务端
ReadFromUDP后没及时清空缓冲区,或没处理n == 0的情况(空包也是合法 UDP 包) - 客户端发包后立刻关闭连接,而服务端响应还没发出,导致响应被丢弃(UDP 不保证送达)
调试时先用 netstat -anu | grep 8080(Linux/macOS)或 Get-NetUDPEndpoint | ? LocalPort -eq 8080(PowerShell)确认端口确实在监听;再用 nc -u 127.0.0.1 8080 手动发包测试通路。


















