Press "Enter" to skip to content

UDP服务搭建

UDP服务搭建

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

1764295263473

什么是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调用接口

1764296895595

客户端:

1764296904457