go: 如何编写一个正确的udp服务端
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)
}
注意点:
- data可以在循环外创建,复用即可。每次
ReadFromUDP并不会受到上次数据残留的影响。 - 不要在
for中执行重逻辑,避免等待太久时间udp大量丢包。所以每次收到udpMsg,都交给go协程来处理。 - raw必须每次在循环内创建,否则在后面的
go并发会踩内存。 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服务端的更多相关文章
- 编写一个简单的TCP服务端和客户端
下面的实验环境是linux系统. 效果如下: 1.启动服务端程序,监听在6666端口上 2.启动客户端,与服务端建立TCP连接 3.建立完TCP连接,在客户端上向服务端发送消息 4.断开连接 实现 ...
- [C语言]一个很实用的服务端和客户端进行TCP通信的实例
本文给出一个很实用的服务端和客户端进行TCP通信的小例子.具体实现上非常简单,只是平时编写类似程序,具体步骤经常忘记,还要总是查,暂且将其记下来,方便以后参考. (1)客户端程序,编写一个文件clie ...
- socket创建UDP服务端和客户端
UDP服务端代码示例: from socket import * #1.创建数据报套接字 sockfd = socket(AF_INET, SOCK_DGRAM) #2.绑定服务端地 sockfd.b ...
- python创建udp服务端和客户端
1.udp服务端server from socket import * from time import ctime HOST = '' PORT = 8888 BUFSIZ = 1024 ADDR ...
- Node.js是一个事件驱动I/O服务端JavaScript环境
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎.目的是为了提供撰写可扩充网络程序,如Web服务.第一个版本由Ryan Dahl于2009年发布,后来,Jo ...
- [C语言]一个很实用的服务端和客户端进行UDP通信的实例
前段时间发了个TCP通信的例子,现在再来一个UDP通信的例子.这些可以作为样本程序,用到开发中.“裸写”socket老是记不住步骤,经常被鄙视…… 下面的例子很简单,写一个UDP的server用于收包 ...
- udp服务端收发数据流程
1.创建服务端的socket以便开始通讯.2.绑定ip以及端口号,这样客户端才能找到这个程序.3.因为本地网卡不止一个所以尽量不写死,一般用""空来表示所有本地网卡.4.接下来开始 ...
- 简单的UDP服务端和客户端示例
UDP的理论不再多说,我这里直接给出一个关于UDP的HelloWorld程序,代码明了,希望对刚入门的学生有所帮助! 当然,实际上,在这块我也刚入门! 首先写服务端代码,服务端邦定本地的IP和端口来监 ...
- socket手写一个简单的web服务端
直接进入正题吧,下面的代码都是我在pycharm中写好,再粘贴上来的 import socket server = socket.socket() server.bind(('127.0.0.1', ...
随机推荐
- python基础练习题(题目 判断101-200之间有多少个素数,并输出所有素数。)
day7 --------------------------------------------------------------- 实例012:100到200的素数 题目 判断101-200之间 ...
- Ubuntu 下 Apache2 和 PHP 服务器环境配置
Ubuntu 下 Apache2 和 PHP 服务器环境配置 1.简介 本文主要是 Ubuntu 下 Apache2 和 PHP 服务器环境配置方法,同样适用于 Debian 系统:Ubuntu 20 ...
- 《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
1.简介 上一篇介绍了POM的基础理论知识和非POM方式写脚本,这篇介绍利用页面工厂类(page factory)去实现POM,通过查看PageFactory类,我们可以知道它是一个初始化一个页面实例 ...
- IDEA2021.2安装lombok插件(借鉴前辈)
lomhok下载地址: https://plugins.jetbrains.com/plugin/6317-lombok/versions CSDN关注斧头湖懒客 一,下载lombok插件我这里下载的 ...
- Linux-简-脚本集合
编写脚本,求100以内所有正奇数之和 while加 if 判断 #!/bin/bash # # # sum=0 i=1 while (($i<=100));do sur=$[i%2] if [ ...
- epoll 函数解析
本文参考社长的 TinyWebServer 庖丁解牛 epoll 常用API epoll_create 函数 #include <sys/epoll.h> int epoll_create ...
- this-4
ES6函数里的this指的是定义这个函数时外层代码的this,可以理解为:1.ES6箭头函数没有自己的this:2.ES6箭头函数的this是外层代码(定义时,非执行时,也就是词法作用域)this的引 ...
- MyBatisPlus实现分页和查询操作就这么简单
<SpringBoot整合MybatisPlus基本的增删改查,保姆级教程>在这篇文章中,我们详细介绍了分页的具体实现方法.但是,在日常的开发中还需要搜索功能的.下面让我们一起动起手来,实 ...
- GIL与普通互斥锁区别,死锁现象,信号量,event事件,进程池与线程池,协程
GIL与普通互斥锁区别 GIL锁和互斥锁的异同点 相同: 都是为了解决解释器中多个线程资源竞争的问题 异: 1.互斥锁是Python代码层面的锁,解决Python程序中多线程共享资源的问题(线程数据共 ...
- JS 的立即执行函数
JS 的立即执行函数 本文写于 2019 年 12 月 7 日 其实 ES6 之后有了之后,很多之前的用法都没必要了,立即执行函数就是其一. 今天看到一道面试题: 请「用自己的语言」简述 立即执行函数 ...