
UDP 报文捕获分两种场景:一种是作为服务端接收业务数据,另一种是底层抓包分析所有经过网卡的 UDP 流量。两者技术路径完全不同,不能混用。
ListenUDP + ReadFromUDP 是接收自己监听端口的业务 UDP 数据
这是最常用、最轻量的方式,适用于你已知目标端口(比如 DNS 53、NTP 123 或自定义服务),且只关心发给本机该端口的数据。
net.ListenUDP 绑定本地地址后,ReadFromUDP 阻塞等待数据;返回值包含数据字节切片和发送方 *net.UDPAddr,必须提供足够大的缓冲区(常见 1500–65536 字节),否则截断错误只在 ReadFromUDP 调用时暴露,比如 read: connection reset by peer(对方 ICMP port unreachable)、io.EOF(连接被关闭)或 invalid argument(缓冲区太小)不要用 conn.Read —— 它只在 DialUDP 创建的已连接 socket 上可用;ListenUDP 返回的是无连接 socket,必须用 ReadFromUDP并发处理需配合 goroutine,但注意每个 ReadFromUDP 调用是独占的,别在多个 goroutine 里共用同一个 *net.UDPConn
示例关键片段:
addr, _ := net.ResolveUDPAddr("udp", ":53")conn, _ := net.ListenUDP("udp", addr)defer conn.Close()buf := make([]byte, 65536)for { n, clientAddr, err := conn.ReadFromUDP(buf) if err != nil { log.Printf("Read error: %v", err) continue } // 处理 buf[:n] 和 clientAddr}
pcap.OpenLive + 过滤器 是抓取网卡上所有 UDP 包(含非本机目标)
这属于网络嗅探(sniffing),需要 root 权限(Linux/macOS)或管理员权限(Windows),用于调试、监控、安全分析等场景,不适用于常规业务通信。
立即学习“go语言免费学习笔记(深入)”;
用 github.com/google/gopacket/pcap 的 pcap.OpenLive 打开网卡,参数如 65536 是最大捕获长度,设太小会丢载荷;true 表示混杂模式(能抓到非本机目标包)必须加 BPF 过滤器(如 "udp" 或 "udp port 53"),否则会收到所有协议流量,CPU 和内存压力陡增错误发生在 OpenLive(设备不存在、无权限、参数非法)或 handle.ReadPacketData()(超时、中断),不是每包都返回 error解析时用 gopacket.DecodeOptions.NoCopy 可避免重复拷贝,但需确保原始字节在解析期间不被覆盖
示例关键片段:
handle, err := pcap.OpenLive("eth0", 65536, true, pcap.BlockForever)if err != nil { log.Fatal(err)}defer handle.Close()// 设置 UDP 过滤器err = handle.SetBPFFilter("udp")if err != nil { log.Fatal(err)}packetSource := gopacket.NewPacketSource(handle, handle.LinkType())for packet := range packetSource.Packets() { if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil { udp := udpLayer.(*layers.UDP) fmt.Printf("UDP %s:%d → %s:%d\n", packet.NetworkLayer().NetworkFlow().Src(), udp.SrcPort, packet.NetworkLayer().NetworkFlow().Dst(), udp.DstPort) }}
WriteToUDP 不报错 ≠ 数据送达,也不能靠它“探测端口”
很多人误以为调用 WriteToUDP 成功就代表对端 UDP 服务可达——这是根本性误解。
WriteToUDP 返回 n, nil 仅表示数据已提交给内核发送队列,**不保证送达、不触发任何网络层确认**真正的错误(如 syscall.EHOSTUNREACH、syscall.EPORTUNREACH)可能延迟数秒才通过 ICMP 回包触发,且不一定返回给你的 socket(取决于系统配置和中间设备)无法用 WriteToUDP 可靠判断 UDP 端口是否开放:没响应可能是服务没启、防火墙丢包、ICMP 被禁、或服务本身就不应答(如很多 UDP 服务是纯单向接收)若真要探测,必须搭配应用层应答机制(如发请求 + 设定超时等待响应),或用 net.DialUDP + Write + Read(要求对方也实现应答逻辑)
真正容易被忽略的是:UDP 通信没有“连接状态”,ReadFromUDP 和 WriteToUDP 的错误时机与语义和 TCP 完全不同;而抓包(pcap)是另一套权限模型和性能模型,不能当作常规 I/O 替代方案。选哪条路,先想清楚你要的是业务数据,还是链路诊断数据。

评论(0)