udp的服务端有一个大坑,即如果收包不及时,在系统缓冲写满后,将大量丢包。

在网上通常的示例中,一般在for循环中执行操作逻辑。这在生产环境将是一个隐患。是的,俺就翻车了。

go强大简易的并发能力可以用在处理udp数据上。

	PoolSizeUDP := 1472
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
}
// 如果还不行,考虑把系统的buffer设大一点
// listener.SetReadBuffer(1024 * 1024 * 8)
// listener.SetWriteBuffer(1024 * 1024 * 8)
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可以在循环外创建,复用即可。每次ReadFromUDP并不会受到上次数据残留的影响。
  2. 不要在for中执行重逻辑,避免等待太久时间udp大量丢包。所以每次收到udpMsg,都交给go协程来处理。
  3. raw必须每次在循环内创建,否则在后面的go并发会踩内存。
  4. SetReadBuffer这个配置很有用

更新:上面的示例为了避免在后续的go中,有不可控的异步操作引用了数据导致踩内存,每次收消息都分配了新的[]byte

raw := make([]byte, n) // 重点注意,每次循环都必须创建新的raw变量,否则踩内存
copy(raw, data[:n])

经大佬提醒,这其实是一个不小的开销。如果go中执行的行为可控,引入sync.Pool可以很方便的做内存复用。

var udpBytesPool = sync.Pool{
New: func() any {
return make([]byte, PoolSizeUDP)
},
}
......
for {
data := udpBytesPool.Get().([]byte)
n, addr, err := listener.ReadFromUDP(data)
if err != nil {
logrus.Errorf("RunUdpServer ReadFromUDP err: %v", err)
continue
}
go func(){
defer udpBytesPool.Put(data) // 注意,在协程退出执行这个操作时,一定确认 data不会再被引用了
// do sth
}()
}

go: 如何编写一个正确的udp服务端的更多相关文章

  1. 编写一个简单的TCP服务端和客户端

    下面的实验环境是linux系统. 效果如下: 1.启动服务端程序,监听在6666端口上  2.启动客户端,与服务端建立TCP连接  3.建立完TCP连接,在客户端上向服务端发送消息 4.断开连接 实现 ...

  2. [C语言]一个很实用的服务端和客户端进行TCP通信的实例

    本文给出一个很实用的服务端和客户端进行TCP通信的小例子.具体实现上非常简单,只是平时编写类似程序,具体步骤经常忘记,还要总是查,暂且将其记下来,方便以后参考. (1)客户端程序,编写一个文件clie ...

  3. socket创建UDP服务端和客户端

    UDP服务端代码示例: from socket import * #1.创建数据报套接字 sockfd = socket(AF_INET, SOCK_DGRAM) #2.绑定服务端地 sockfd.b ...

  4. python创建udp服务端和客户端

    1.udp服务端server from socket import * from time import ctime HOST = '' PORT = 8888 BUFSIZ = 1024 ADDR ...

  5. Node.js是一个事件驱动I/O服务端JavaScript环境

    Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎.目的是为了提供撰写可扩充网络程序,如Web服务.第一个版本由Ryan Dahl于2009年发布,后来,Jo ...

  6. [C语言]一个很实用的服务端和客户端进行UDP通信的实例

    前段时间发了个TCP通信的例子,现在再来一个UDP通信的例子.这些可以作为样本程序,用到开发中.“裸写”socket老是记不住步骤,经常被鄙视…… 下面的例子很简单,写一个UDP的server用于收包 ...

  7. udp服务端收发数据流程

    1.创建服务端的socket以便开始通讯.2.绑定ip以及端口号,这样客户端才能找到这个程序.3.因为本地网卡不止一个所以尽量不写死,一般用""空来表示所有本地网卡.4.接下来开始 ...

  8. 简单的UDP服务端和客户端示例

    UDP的理论不再多说,我这里直接给出一个关于UDP的HelloWorld程序,代码明了,希望对刚入门的学生有所帮助! 当然,实际上,在这块我也刚入门! 首先写服务端代码,服务端邦定本地的IP和端口来监 ...

  9. socket手写一个简单的web服务端

    直接进入正题吧,下面的代码都是我在pycharm中写好,再粘贴上来的 import socket server = socket.socket() server.bind(('127.0.0.1', ...

随机推荐

  1. python基础练习题(题目 判断101-200之间有多少个素数,并输出所有素数。)

    day7 --------------------------------------------------------------- 实例012:100到200的素数 题目 判断101-200之间 ...

  2. Ubuntu 下 Apache2 和 PHP 服务器环境配置

    Ubuntu 下 Apache2 和 PHP 服务器环境配置 1.简介 本文主要是 Ubuntu 下 Apache2 和 PHP 服务器环境配置方法,同样适用于 Debian 系统:Ubuntu 20 ...

  3. 《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)

    1.简介 上一篇介绍了POM的基础理论知识和非POM方式写脚本,这篇介绍利用页面工厂类(page factory)去实现POM,通过查看PageFactory类,我们可以知道它是一个初始化一个页面实例 ...

  4. IDEA2021.2安装lombok插件(借鉴前辈)

    lomhok下载地址: https://plugins.jetbrains.com/plugin/6317-lombok/versions CSDN关注斧头湖懒客 一,下载lombok插件我这里下载的 ...

  5. Linux-简-脚本集合

    编写脚本,求100以内所有正奇数之和 while加 if 判断 #!/bin/bash # # # sum=0 i=1 while (($i<=100));do sur=$[i%2] if [ ...

  6. epoll 函数解析

    本文参考社长的 TinyWebServer 庖丁解牛 epoll 常用API epoll_create 函数 #include <sys/epoll.h> int epoll_create ...

  7. this-4

    ES6函数里的this指的是定义这个函数时外层代码的this,可以理解为:1.ES6箭头函数没有自己的this:2.ES6箭头函数的this是外层代码(定义时,非执行时,也就是词法作用域)this的引 ...

  8. MyBatisPlus实现分页和查询操作就这么简单

    <SpringBoot整合MybatisPlus基本的增删改查,保姆级教程>在这篇文章中,我们详细介绍了分页的具体实现方法.但是,在日常的开发中还需要搜索功能的.下面让我们一起动起手来,实 ...

  9. GIL与普通互斥锁区别,死锁现象,信号量,event事件,进程池与线程池,协程

    GIL与普通互斥锁区别 GIL锁和互斥锁的异同点 相同: 都是为了解决解释器中多个线程资源竞争的问题 异: 1.互斥锁是Python代码层面的锁,解决Python程序中多线程共享资源的问题(线程数据共 ...

  10. JS 的立即执行函数

    JS 的立即执行函数 本文写于 2019 年 12 月 7 日 其实 ES6 之后有了之后,很多之前的用法都没必要了,立即执行函数就是其一. 今天看到一道面试题: 请「用自己的语言」简述 立即执行函数 ...