udp服务端需用net.listenudp监听:8080地址,通过readfromudp和writetoudp在goroutine中循环收发;控制台输入与udp收发应分goroutine并用channel通信;消息加\x00分隔符防粘包;局域网不通优先查防火墙、绑定地址和网络连通性。

UDP服务端怎么监听并收发消息
Go 的 net.ListenUDP 是起点,但新手常卡在地址绑定和循环读写上。它不自动处理连接(因为 UDP 无连接),你得自己用 ReadFromUDP 和 WriteToUDP 配合缓冲区收发数据。
常见错误是只调用一次 ReadFromUDP 就退出,导致只能收一条;或者把 localhost 写死成 127.0.0.1:8080 却没意识到这会拒绝其他机器发来的包(需用 :8080 绑定所有接口)。
实操建议:
- 监听地址用
:8080而非127.0.0.1:8080,方便局域网内多终端测试 - 用固定大小缓冲区(如
make([]byte, 1024)),别用strings.NewReader或bytes.Buffer混淆流式逻辑 - 收发必须在 goroutine 中持续运行,否则阻塞主线程,控制台输入就卡住
- 注意
ReadFromUDP返回的addr是发送方地址,后续回复要用它,不能硬编码目标 IP
控制台输入和 UDP 收发如何不互相阻塞
Go 控制台读取(fmt.Scanln 或 bufio.NewReader(os.Stdin).ReadString('\n'))默认是同步阻塞的,如果和 UDP 接收共用一个 goroutine,一等输入就收不到消息;全放 goroutine 又容易丢输入或乱序。
立即学习“go语言免费学习笔记(深入)”;
根本原因是标准输入和网络 I/O 属于两类阻塞源,不能靠单个 select 统一调度(os.Stdin 不是 chan,不能直接进 select)。
实操建议:
- 为 stdin 单独起 goroutine,读到内容后发到
chan string;UDP 接收也走自己的 goroutine,发到另一个chan []byte - 主 goroutine 用
select同时监听两个 channel,避免任一端卡死 - 不要用
fmt.Scanln,它对空格和换行敏感,改用bufio.NewReader(os.Stdin).ReadString('\n')更可控 - 输入 channel 建议带缓冲(如
make(chan string, 10)),防止快速连按回车时丢失
UDP 消息怎么加简单协议头防粘包和误读
UDP 不保证顺序、不分包也不合并,但实际中连续发两条短消息可能被系统合并进一个 IP 包(尤其 localhost 测试时),或因 MTU 截断。没有协议头,接收端无法判断哪段是用户名、哪段是正文。
不需要搞 TLV 或 protobuf,一个字节分隔符 + 固定前缀就够用。重点不是“标准”,而是两端一致且能容错。
实操建议:
- 发送前拼接:
username + "\x00" + message(\x00作分隔符,比空格/冒号更不易冲突) - 接收后用
bytes.SplitN(data, []byte("\x00"), 2)拆,长度不足 2 就丢弃——这是最简单的校验 - 避免用
string(data)直接转,UDP 可能含非法 UTF-8 字节;日志打印时用fmt.Printf("%q", data)查看原始字节 - 不加长度字段不是因为“够用”,而是因为控制台小程序里人工调试时,长度字段反而增加解析负担
为什么本地测试通了,局域网两台电脑却收不到
最常见的是防火墙拦截、端口未开放,或 UDP 绑定地址写死了 127.0.0.1。另一个隐蔽问题是:Windows/macOS 的 Wi-Fi 共享设置或“防火墙允许应用通信”列表里,go run 启动的临时程序默认被拒。
还有种情况是路由器开启了 AP 隔离(Client Isolation),让同一 Wi-Fi 下的设备彼此 ping 不通,UDP 自然也发不出去。
实操建议:
- 先用
nc -u -l 8080(Linux/macOS)或Test-NetConnection -Port 8080 -ComputerName 192.168.x.x -Udp(PowerShell)确认端口可达 - 服务端绑定用
:8080,客户端发往对方真实局域网 IP(如192.168.1.102:8080),别用localhost - 关掉双方防火墙试一次,再逐个加回规则;macOS 注意“防火墙选项”里的“阻止所有传入连接”是否开启
- 用
ifconfig(macOS/Linux)或ipconfig(Windows)确认双方在同一子网,比如都是192.168.1.x
UDP 没有连接状态,所以“连不上”的问题永远不在 Go 代码本身,而在网络路径、地址绑定、系统策略这三层。查的时候从物理层(能不能 ping 通)开始,一层层往上推,别一上来就翻 Go 文档。











