英文:
Strange behaviour of golang UDP server
问题
我用go语言编写了一个简单的UDP服务器。
当我运行go run udp.go
时,它会打印我发送给它的所有数据包。但是当我运行go run udp.go > out
时,当客户端停止时,它停止将stdout
传递给out
文件。
客户端是一个简单的程序,发送了10k个请求。所以在文件中,我大约有50%的发送包。当我再次运行客户端时,out
文件会再次增长,直到客户端脚本完成。
服务器代码:
package main
import (
"net"
"fmt"
)
func main() {
addr, _ := net.ResolveUDPAddr("udp", ":2000")
sock, _ := net.ListenUDP("udp", addr)
i := 0
for {
i++
buf := make([]byte, 1024)
rlen, _, err := sock.ReadFromUDP(buf)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(buf[0:rlen]))
fmt.Println(i)
//go handlePacket(buf, rlen)
}
}
以下是客户端代码:
package main
import (
"net"
"fmt"
)
func main() {
num := 0
for i := 0; i < 100; i++ {
for j := 0; j < 100; j++ {
num++
con, _ := net.Dial("udp", "127.0.0.1:2000")
fmt.Println(num)
buf := []byte("bla bla bla I am the packet")
_, err := con.Write(buf)
if err != nil {
fmt.Println(err)
}
}
}
}
希望对你有帮助!
英文:
I wrote a simple UDP server in go.
When I do go run udp.go
it prints all packages I send to it. But when running go run udp.go > out
it stops passing stdout
to the out
file when the client stops.
The client is simple program that sends 10k requests. So in the file I have around 50% of sent packages. When I run the client again, the out
file grows again until the client script finishes.
Server code:
package main
import (
"net"
"fmt"
)
func main() {
addr, _ := net.ResolveUDPAddr("udp", ":2000")
sock, _ := net.ListenUDP("udp", addr)
i := 0
for {
i++
buf := make([]byte, 1024)
rlen, _, err := sock.ReadFromUDP(buf)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(buf[0:rlen]))
fmt.Println(i)
//go handlePacket(buf, rlen)
}
}
And here is the client code:
package main
import (
"net"
"fmt"
)
func main() {
num := 0
for i := 0; i < 100; i++ {
for j := 0; j < 100; j++ {
num++
con, _ := net.Dial("udp", "127.0.0.1:2000")
fmt.Println(num)
buf := []byte("bla bla bla I am the packet")
_, err := con.Write(buf)
if err != nil {
fmt.Println(err)
}
}
}
}
答案1
得分: 15
正如你怀疑的那样,由于UDP的特性,这似乎是UDP数据包丢失的问题。因为UDP是无连接的,客户端不关心服务器是否可用或准备好接收数据。所以如果服务器正在忙于处理数据,它将无法处理下一个传入的数据报。你可以使用netstat -u
命令来检查(其中应该包含UDP数据包丢失的信息)。我也遇到了同样的问题,即服务器(接收端)无法跟上发送的数据包。
你可以尝试两件事情(第二个对我来说在你的示例中有效):
调用SetReadBuffer。 确保接收套接字具有足够的缓冲区来处理你发送的所有数据。
sock, _ := net.ListenUDP("udp", addr)
sock.SetReadBuffer(1048576)
在一个go协程中进行所有的数据包处理。 通过确保服务器在你希望其可用于接收数据时不忙于其他工作,尝试增加每秒数据报的数量。即将处理工作移动到一个go协程中,这样就不会阻塞ReadFromUDP()。
// 使用一个计数参数重新定义你的go handlePacket(buf, rlen)函数
func handlePacket(buf []byte, rlen int, count int) {
fmt.Println(string(buf[0:rlen]))
fmt.Println(count)
}
...
go handlePacket(buf, rlen, i)
最后一个选项:
最后,也许不是你想要的,你可以在客户端中加入延迟,以减慢数据发送速率,从而解决问题。例如:
buf := []byte("bla bla bla I am the packet")
time.Sleep(100 * time.Millisecond)
_, err := con.Write(buf)
英文:
As you suspected, it seems like UDP packet loss due to the nature of UDP. Because UDP is connectionless, the client doesn't care if the server is available or ready to receive data. So if the server is busy processing, it won't be available to handle the next incoming datagram. You can check with netstat -u
(which should include UDP packet loss info). I ran into the same thing, in which the server (receive side) could not keep up with the packets sent.
You can try two things (the second worked for me with your example):
Call SetReadBuffer. Ensure the receive socket has enough buffering to handle everything you throw at it.
sock, _ := net.ListenUDP("udp", addr)
sock.SetReadBuffer(1048576)
Do all packet processing in a go routine. Try to increase the datagrams per second by ensuring the server isn't busy doing other work when you want it to be available to receive. i.e. Move the processing work to a go routine, so you don't hold up ReadFromUDP().
//Reintroduce your go handlePacket(buf, rlen) with a count param
func handlePacket(buf []byte, rlen int, count int)
fmt.Println(string(buf[0:rlen]))
fmt.Println(count)
}
...
go handlePacket(buf, rlen, i)
One final option:
Lastly, and probably not what you want, you put a sleep in your client which would slow down the rate and would also remove the problem. e.g.
buf := []byte("bla bla bla I am the packet")
time.Sleep(100 * time.Millisecond)
_, err := con.Write(buf)
答案2
得分: 1
尝试在写入语句后同步标准输出。
os.Stdout.Sync()
英文:
Try syncing stdout after the write statements.
os.Stdout.Sync()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论