go udp需正确绑定端口、处理65507字节限制、并发读写隔离、用setreaddeadline控制单次i/o超时,应用层须自行实现可靠性机制。
Go 语言原生 net 包对 UDP 的支持简洁直接,但容易在地址绑定、数据截断、并发读写和超时控制上出问题。用对 UDPConn 是关键,不是套个 ListenUDP 就能稳定传数据。
如何正确创建并绑定 UDP 端口(避免 address already in use)
常见错误是硬编码 "localhost:8080" 或 ":8080" 后反复运行报错。根本原因是端口被前一次进程残留占用,或未正确关闭连接。
-
ListenUDP的地址参数必须是"IP:port"格式,":8080"表示监听所有本地 IP,"127.0.0.1:8080"只响应本机回环;生产环境慎用"0.0.0.0:8080" - 调用后务必检查返回 error,尤其
syscall.EADDRINUSE—— 此时应加net.ListenConfig{Control: setReuseAddr}或等几秒重试 - 使用
defer conn.Close()不够,若程序 panic 或提前 return,需确保conn被显式关掉;建议用sync.Once或 context 控制生命周期
为什么 recvfrom 总是只收到前 65507 字节(UDP 数据包大小限制)
UDP 单包理论最大为 65535 字节,但 IPv4 头部占 20 字节、UDP 头部占 8 字节,实际可用载荷上限是 65507 字节。超过会直接被内核丢弃,且不通知应用层。
- Go 中
conn.ReadFromUDP(buf)返回的n永远 ≤len(buf),但不会告诉你是否被截断 —— 它只按内核交付的完整 UDP 包读取 - 如果业务需要传输大块数据(如日志、图片),必须在应用层分片 + 编号 + 重组;不要指望 OS 帮你做“流式 UDP”
- 服务端
buf建议至少设为 65536,否则小包也可能被截断;客户端发包前用len(data) > 65507主动拒绝或报错
如何安全地并发读写同一个 *UDPConn
*UDPConn 本身是并发安全的,但读写共用一个缓冲区或共享状态(如计数器、map)时极易出竞态。Go 的 go tool race 很容易发现这类问题。