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', ...
随机推荐
- 计算属性、侦听属性、局部与全局组件使用、组件通信(父子互传)、ref属性、动态组件和keep-alive、插槽
今日内容概要 计算属性 侦听属性 局部组件和全局组件 组件通信之父传子 组件通信之子传父 ref属性(组件间通信) 动态组件和keep-alive 插槽 内容详细 1.计算属性 # 插值的普通函数,只 ...
- ThinkPHP3.2.3反序列化链子分析
前言 目前官方已经不再维护ThinkPHP3.2.3,本文仅对ThinkPHP3.2.3反序列化链子进行复现,如有纰漏,还望指正. 环境介绍 MAMP pro PhpStorm Xdebug 利用条件 ...
- 2021.11.10 fail树
2021.11.10 fail树 https://blog.csdn.net/niiick/article/details/87947160 1. AC自动机与fail树的神奇关系 1.1 AC自动机 ...
- 【vue】$attrs的作用和使用方法
之前一直不了解$attrs的作用和使用场景,然后自己翻阅了相关资料整理了下,如有不对的地方请大家指教 $attrs: $attrs是vue版本2.40以上新增的属性: 使用场景: vue项目里面,大家 ...
- Promql基础语法2
数据样本 直方图类型 delta函数 运算操作 数学运算 node_disk_info / 100 当瞬时向量与标量之间进行数学运算时,数学运算符会依次作用域瞬时向量中的每一个样本值,从而得到一组新的 ...
- HCNP Routing&Switching之MUX VLAN
前文我们了解了代理ARP相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16188230.html:今天我们再来聊一聊vlan隔离相关话题MUX VLA ...
- 全场景AI推理引擎MindSpore Lite, 助力HMS Core视频编辑服务打造更智能的剪辑体验
移动互联网的发展给人们的社交和娱乐方式带来了很大的改变,以vlog.短视频等为代表的新兴文化样态正受到越来越多人的青睐.同时,随着AI智能.美颜修图等功能在图像视频编辑App中的应用,促使视频编辑效率 ...
- 基本命令学习 -(4)链接文件:ln命令
关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ 前言 在Windows系统中,快捷方式是指向原始文件的一个链接文件,原文件一旦被删除或剪切到其 ...
- JuiceFS 在数据湖存储架构上的探索
大家好,我是来自 Juicedata 的高昌健,今天想跟大家分享的主题是<JuiceFS 在数据湖存储架构上的探索>,以下是今天分享的提纲: 首先我会简单的介绍一下大数据存储架构变迁以及它 ...
- 不使用比较和条件判断实现min函数的一种方法
不使用比较和条件判断实现min函数,参数为两个32位无符号int. 面试的时候遇到的题目,感觉很有意思. 搜了一下多数现有的解法都是仅有两种限制之一,即要么仅要求不能使用比较,要么仅要求不能使用条件判 ...