golang UDP服务器的奇怪行为

huangapple go评论149阅读模式
英文:

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 &gt; 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 (
  &quot;net&quot;

  &quot;fmt&quot;
)

func main() {
  addr, _ := net.ResolveUDPAddr(&quot;udp&quot;, &quot;:2000&quot;)
  sock, _ := net.ListenUDP(&quot;udp&quot;, 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 (
  &quot;net&quot;

  &quot;fmt&quot;
)

func main() {

  num := 0
  for i := 0; i &lt; 100; i++ {
    for j := 0; j &lt; 100; j++ {
      num++
      con, _ := net.Dial(&quot;udp&quot;, &quot;127.0.0.1:2000&quot;)
      fmt.Println(num)
      buf := []byte(&quot;bla bla bla I am the packet&quot;)
      _, 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(&quot;udp&quot;, 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(&quot;bla bla bla I am the packet&quot;)
time.Sleep(100 * time.Millisecond)
_, err := con.Write(buf)

答案2

得分: 1

尝试在写入语句后同步标准输出。

os.Stdout.Sync()
英文:

Try syncing stdout after the write statements.

os.Stdout.Sync() 

huangapple
  • 本文由 发表于 2013年10月29日 20:20:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/19658052.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定