前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go: 如何编写一个正确的udp服务端

go: 如何编写一个正确的udp服务端

作者头像
超级大猪
发布2022-11-29 17:24:31
5510
发布2022-11-29 17:24:31
举报

udp的服务端有一个大坑,即如果收包不及时,在系统缓冲写满后,将大量丢包。 在网上通常的示例中,一般在for循环中执行操作逻辑。这在生产环境将是一个隐患。 go强大简易的并发能力可以用在处理udp数据上。

 PoolSizeUDP :=  
    listener, err := net.ListenUDP("udp", &net.UDPAddr{ 
        IP:   net.ParseIP(listenIP), 
 Port: port, 
 }) 
 if err != nil { 
        logrus.Fatalf("RunUdpServer failed to listen: %v", err) 
 return nil 
 } 
 var data = make([]byte, PoolSizeUDP) 
    chLimit := make(chan int, 64) // 最多创建64个协程,避免内存爆炸 
 for { 
 select { 
 case <-ctx.Done(): 
 return nil 
 default: 
 } 
        n, addr, err := listener.ReadFromUDP(data) 
 if err != nil { 
            logrus.Errorf("RunUdpServer ReadFromUDP err: %v", err) 
 continue 
 } 
        raw := make([]byte, n) // 重点注意,每次循环都必须创建新的raw变量,否则踩内存 
        copy(raw, data[:n]) 
        chLimit <- 1 
        go func(udpMsg []byte) { 
 // 拿 udpMsg 做点什么 
            defer func() { 
 <-chLimit 
 }() 
 DoSth(udpMsg) 
 }(raw) 
 } 

注意点:

  1. data可以在循环外创建,复用即可。
  2. 不要在for中执行重逻辑,避免等待太久时间udp大量丢包。所以每次收到udpMsg,都交给go协程来处理。
  3. raw必须每次在循环内创建,否则在后面的go并发必然踩内存。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-06-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档