UDP服务搭建
背景:客户有个小的环控设备,给用户体验温度环境的,采用我们温湿度传感器采集的数据,但用户仅提供了一个UDP接收地址,要求我们将数据传递到该地址

什么是UDP
UDP是一种无连接,不可靠,轻量级传输协议,用于快速发送数据包,但不保证数据一定能送达,不保证顺序,也不进行重传
特点
| 特性 | UDP | TCP |
|---|---|---|
| 连接方式 | 无连接(直接发数据) | 面向连接(先握手建立连接) |
| 可靠性 | 不可靠(不保证送达) | 可靠(保证传达,有序,不丢包) |
| 数据顺序 | 不保证顺序 | 保证顺序 |
| 数据重传 | 不重传丢失的数据包 | 会重传丢失或出错的数据包 |
| 流量控制/拥塞控制 | 没有 | 有(防止网络拥堵) |
| 传输速度 | 快(开销小,延迟低) | 相对慢(因为要保证可靠) |
| 头部大小 | 8字节(很小) | 至少20字节(较大) |
| 应用场景 | 实时性要求高,允许少量丢包的场景 | 要求可靠传输的场景(如网页,文件) |
工作原理
1.不需要事先建立连接:发送方直接把数据打包成UDP的数据包,然后扔到网络上,目标地址写清楚就行
2、数据包独立传输:每个UDP数据包都是独立的,可能会走不同的路径,也可能丢失,乱序
3、不关心对方是否收到:发出去就不管了,不会确认,不会重发,不会排序
4.适合快速发送:因为没有复杂的控制机制,所以速度快,开销小,实时性强
实现
在golang中依靠的是net
func NewUDPSender(serverAddr string) (*UDPSender, error) {
udpAddr, err := net.ResolveUDPAddr("udp", serverAddr)
if err != nil {
return nil, err
}
conn, err := net.DialUDP("udp", nil, udpAddr)
if err != nil {
return nil, err
}
return &UDPSender{
conn: conn,
addr: udpAddr,
}, nil
}
func (s *UDPSender) Send(data []byte) error {
s.mu.Lock()
defer s.mu.Unlock()
_, err := s.conn.Write(data)
return err
}
func (s *UDPSender) Close() error {
return s.conn.Close()
}
调用:搭建好udp服务后,在需要发送udp数据的地方调用即可
// 获取到发送地址
udpIp := Common{}.GetUDPServer()
udpSender, err := udp.NewUdpSender(udpIp)
// 延迟关闭
defer udpSender.Close()
if err != nil {
logger.Info(ctx, "udp连接失败", logger.Any("err: ", err))
} else {
type UDPRes struct {
Temp float64 `json:"temp"`
Timestamp int64 `json:"timestamp"`
}
var res UDPRes
res.Temp = TargetTemp
res.Timestamp = TargetTime
logger.Info(ctx, "udp发送内容", logger.Any("res: ", res))
resBytes, _ := json.Marshal(&res)
// 将 UTF-8的JSON字节转换为GBK编码字节
gbkBytes, _ := bd.UTF8ToGBK(resBytes)
logger.Info(ctx, "udp发送内容", logger.Any("gbkBytes: ", gbkBytes))
err = udpSender.Send(gbkBytes)
logger.Info(ctx, "udp数据发送结果", logger.Any("err: ", err))
logger.Info(ctx, "GBK 解码回 UTF-8 后的内容:", logger.String("gbkBytes: ", string(gbkBytes)))
}
func (bd BrewingData) UTF8ToGBK(utf8Bytes []byte) ([]byte, error) {
// 创建一个 GBK 编码器
gbkEncoder := simplifiedchinese.GBK.NewEncoder()
// 使用 transform.Bytes 进行转换
gbkBytes, _, err := transform.Bytes(gbkEncoder, utf8Bytes)
return gbkBytes, err
}
验证
使用postman调用接口

客户端:
