我有一个简单的 UDP 服务器,它侦听数据包,等待 50 毫秒,就像正在执行操作一样,然后将消息打印到终端。这是服务器代码:
package main
import (
"fmt"
"log"
"log/slog"
"net"
"time"
)
func main() {
udpAddr, err := net.ResolveUDPAddr("udp", "0.0.0.0:8080")
if err != nil {
log.Fatal(err)
}
conn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
log.Fatal(err)
}
slog.Info("UDP server listening", "addr", udpAddr, "workers", numCpu)
go startWorker(0, conn)
// Block forever
<-make(chan struct{})
}
func startWorker(id int, conn *net.UDPConn) {
slog.Info("Starting worker", "id", id)
i := 0
for {
buf := make([]byte, 1024)
_, _, err := conn.ReadFromUDP(buf)
if err != nil {
slog.Error("failed to read UDP message", "err", err, "worker", id)
continue
}
time.Sleep(50 * time.Millisecond)
fmt.Print(i, " > ", string(buf))
i += 1
}
}
我有一个 go 客户端代码,它只是向该服务器发送一次字符串消息。这是客户端代码:
package main
import (
"log"
"net"
)
func main() {
udpAddr, err := net.ResolveUDPAddr("udp", "0.0.0.0:8080")
if err != nil {
log.Fatal(err)
}
conn, err := net.DialUDP("udp", nil, udpAddr)
if err != nil {
log.Fatal(err)
}
// Send a message to the server
_, err = conn.Write([]byte("Hello UDP Server\n"))
if err != nil {
log.Fatal(err)
}
}
我想测试服务器可以处理多少数据包。所以我所做的是,我按顺序运行客户端代码 10000 次,看看将处理其中的多少个。但每次只处理大约 400-500 个数据包。这是我从终端进行测试的方法:
time (for i in $(seq 10000); do ./client; done)
没有错误日志,输出为:
real 0m12,538s
user 0m10,667s
sys 0m4,014s
我认为这可能是由于操作系统缓冲区限制而导致的问题。所以我在服务器代码中
go startWorker(id, conn)
之前添加了以下代码:
// 1 MB
if err = conn.SetReadBuffer(1024 * 1024 * 1024); err != nil {
log.Fatal(err)
}
进行完全相同的测试后,处理的数据包数量变为 600-700。对于 10000 个这个简单的“Hello UDP Server”,1 MB 缓冲区不可能不够 “消息。任何人都可以向我解释这种行为背后的原因以及如何解决它吗?
P.S.:我使用的是 Ubuntu 22.04
尝试增加操作系统上 UDP 缓冲区的大小。您可以根据您的操作系统使用这些命令:
Linux:
sudo sysctl -w net.core.rmem_max=...
Mac操作系统:
sudo sysctl -w net.inet.udp.recvspace=...
Windows:
在Windows上,您可以通过修改注册表来调整UDP缓冲区大小。相关按键是
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Afd\Parameters\DefaultReceiveWindow
。