如何使用Go语言在UDP接收端解析发送的结构体数据
问题核心原因
- 原始Go代码错误1:结构体
name字段首字母小写为私有属性,所有序列化/反射类库无法读取字段值,序列化后自然为空或乱码 - 原始Go代码错误2:客户端逻辑写反,发送数据应该调用
conn.Write而非Read,且不能直接把结构体作为读写参数,Go运行时不会自动完成内存序列化转换 - CGO版本错误:Go标准库的JSON包无法直接序列化/反序列化CGO定义的C结构体,C类型和Go类型的内存布局、类型映射不兼容,会直接导致序列化失败
实现方案
方案1:纯Go环境实现(无CGO,推荐)
直接使用首字母公开的Go结构体,配合JSON/gob序列化即可快速实现需求:
客户端代码
// client.go package main import ( "encoding/json" "log" "net" ) // 字段首字母大写公开,可加json标签自定义序列化字段名 type Message struct { Name string `json:"name"` } func main() { conn, err := net.Dial("udp", "127.0.0.1:1234") if err != nil { log.Fatal(err) } defer conn.Close() // 序列化结构体为字节流 msg := Message{Name: "hello"} data, err := json.Marshal(msg) if err != nil { log.Fatal(err) } // 发送字节流 _, err = conn.Write(data) if err != nil { log.Fatal(err) } }
服务端代码
// server.go package main import ( "encoding/json" "fmt" "log" "net" ) type Message struct { Name string `json:"name"` } func main() { addr := net.UDPAddr{ Port: 1234, IP: net.ParseIP("127.0.0.1"), } ser, err := net.ListenUDP("udp", &addr) if err != nil { log.Fatal(err) } defer ser.Close() buf := make([]byte, 1024) for { n, remoteAddr, err := ser.ReadFromUDP(buf) if err != nil { log.Println("读取错误:", err) continue } var msg Message // 反序列化字节流到结构体 err = json.Unmarshal(buf[:n], &msg) if err != nil { log.Println("反序列化错误:", err) continue } fmt.Printf("收到来自%s的消息: %+v\n", remoteAddr, msg) // 如需双向回传,序列化返回数据后调用ser.WriteToUDP发回客户端即可 } }
方案2:必须使用C结构体的场景
不要直接序列化C结构体,先把C结构体的字段赋值给对应的Go公开结构体,再做序列化/反序列化操作:
客户端示例逻辑
/* typedef struct { int i; double d; char s; }Message; */ import "C" import ( "encoding/json" "log" "net" ) // 定义对应Go映射结构体 type GoMessage struct { I int `json:"i"` D float64 `json:"d"` S byte `json:"s"` } func main() { conn, err := net.Dial("udp", "127.0.0.1:5000") if err != nil { log.Fatal(err) } defer conn.Close() cMsg := C.Message{i: 123, d: 10.5, s: 'c'} // 转换为Go结构体后再序列化 goMsg := GoMessage{ I: int(cMsg.i), D: float64(cMsg.d), S: byte(cMsg.s), } data, err := json.Marshal(goMsg) if err != nil { log.Fatal(err) } _, err = conn.Write(data) if err != nil { log.Fatal(err) } }
服务端同理,先把收到的字节流反序列化到Go结构体,再赋值给C结构体即可。
注意事项
- UDP是无连接不可靠协议,批量发送数据需要自行处理丢包、乱序、包大小限制(单包不要超过1472字节避免IP分片)问题
- 纯Go服务之间通信也可以用
encoding/gob序列化,性能比JSON更高,无需手动加标签
内容的提问来源于stack exchange,提问作者ka re
相关产品推荐
相关产品推荐

