You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:39:01