
Go 语言中可通过 net.UDPConn 的 WriteTo 方法,复用同一个 UDP socket 向任意数量的不同目标地址发送数据包,无需为每个地址重复创建连接,显著提升性能与资源利用率。
go 语言中可通过 `net.udpconn` 的 `writeto` 方法,复用同一个 udp socket 向任意数量的不同目标地址发送数据包,无需为每个地址重复创建连接,显著提升性能与资源利用率。
在 Go 中,net.Conn 接口面向面向连接的协议(如 TCP),而 UDP 是无连接协议,因此不应强制使用 net.Conn——正确的方式是使用 net.UDPConn,它实现了更底层的 net.PacketConn 接口,支持一对多通信。
✅ 正确做法:复用单个 *net.UDPConn
通过 net.ListenUDP 创建一个绑定到本地地址(如 :0 自动分配端口)的 UDP 连接,之后即可反复调用 WriteTo 向不同远端地址发送数据:
package main
import (
"fmt"
"net"
"time"
)
func main() {
// 创建 UDP socket(监听任意本地地址 + 自动分配端口)
conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: 0})
if err != nil {
panic(err)
}
defer conn.Close()
// 目标主机列表(示例)
targets := []string{"192.168.1.10:8080", "192.168.1.11:8080", "10.0.0.5:9999"}
for _, addrStr := range targets {
addr, err := net.ResolveUDPAddr("udp", addrStr)
if err != nil {
fmt.Printf("resolve %s failed: %v\n", addrStr, err)
continue
}
data := []byte("Hello, UDP!")
n, err := conn.WriteTo(data, addr)
if err != nil {
fmt.Printf("send to %s failed: %v\n", addrStr, err)
continue
}
fmt.Printf("sent %d bytes to %s\n", n, addrStr)
time.Sleep(10 * time.Millisecond) // 可选:避免发包过快
}
}
? 关键点说明
- ListenUDP("udp", &net.UDPAddr{Port: 0}) 返回 *net.UDPConn,它不是 net.Conn,但提供了更符合 UDP 语义的 WriteTo/ReadFrom 方法;
- WriteTo(b []byte, addr net.Addr) 等价于系统调用 sendto(),允许每次指定不同目标地址,完全复用同一文件描述符(fd);
- 若需类型安全或避免接口转换,可直接使用 WriteToUDP(b []byte, addr *net.UDPAddr),二者功能一致,后者省去类型断言;
- UDPConn 支持并发安全写入(WriteTo 是线程安全的),适合高并发批量广播场景。
⚠️ 注意事项
- 不要对每个目标 net.DialUDP —— 这会创建独立 socket,消耗 fd 资源且违背 UDP 设计初衷;
- ListenUDP 绑定的是本地地址,不约束发送目标;目标地址由 WriteTo 动态指定,完全自由;
- 若需接收响应,可用 ReadFrom 配合 UDPAddr 获取来源地址,实现请求-响应双向通信;
- 在生产环境中,建议添加超时控制(如通过 SetDeadline / SetReadDeadline)并妥善处理 io.EOF 或网络错误。
综上,Go 的 net.UDPConn 天然支持“一连多发”,是高效实现 UDP 广播、探测或多目标通信的标准实践。











