UDP请求(数据包)丢失

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

go udp requests (packet) loss

问题

我编写了一个简单的TCP和UDP连接的服务器和客户端。

package main

// server.go

import (
	"fmt"
	"net"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	tcp := 0
	udp := 0

	defer func(o, t *int) {
		fmt.Println(*o, *t)
	}(&tcp, &udp)

	go func() {
		l, err := net.ListenTCP("tcp", &net.TCPAddr{
			IP:   net.ParseIP("0.0.0.0"),
			Port: 3000,
		})
		if err != nil {
			panic(err)
		}

		b := make([]byte, 24)

		for {
			conn, err := l.Accept()
			if err != nil {
				continue
			}

			n, err := conn.Read(b)
			if err != nil {
				continue
			}

			r := string(b[:n])

			if r == "close" {
				conn.Close()
				break
			} else {
				_, err = conn.Write([]byte("pong"))
				if err != nil {
					continue
				}
			}

			conn.Close()
			tcp++
		}

		l.Close()
	}()

	go func() {
		conn, err := net.ListenUDP("udp", &net.UDPAddr{
			IP:   net.ParseIP("0.0.0.0"),
			Port: 3000,
		})
		if err != nil {
			panic(err)
		}

		b := make([]byte, 24)

		for {
			n, addr, err := conn.ReadFromUDP(b)
			if err != nil {
				continue
			}

			r := string(b[:n])

			if r == "close" {
				break
			} else {
				_, err = conn.WriteToUDP([]byte("pong"), addr)
				if err != nil {
					continue
				}
			}

			udp++
		}

		conn.Close()
	}()

	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt, syscall.SIGTERM)

	<-signals
}
package main

// client.go

import (
	"fmt"
	"net"
	"os"
	"os/signal"
	"strconv"
	"sync/atomic"
	"syscall"
	"time"
)

func main() {
	t := "tcp"
	m := "ping"

	c := 1

	if len(os.Args) > 1 {
		t = os.Args[1]
	}

	if len(os.Args) > 2 {
		m = os.Args[2]
	}

	if len(os.Args) > 3 {
		c, _ = strconv.Atoi(os.Args[3])
	}

	tcp := int64(0)
	udp := int64(0)

	defer func(o, t *int64) {
		fmt.Println(*o, *t)
	}(&tcp, &udp)

	if c == 1 {
		if t == "tcp" {
			addr, err := net.ResolveTCPAddr("tcp", ":3000")
			if err != nil {
				panic(err)
			}

			conn, err := net.DialTCP("tcp", nil, addr)
			if err != nil {
				panic(err)
			}

			_, err = conn.Write([]byte(m))
			if err != nil {
				panic(err)
			}

			tcp++
		}

		if t == "udp" {
			addr, err := net.ResolveUDPAddr("udp", ":3000")
			if err != nil {
				panic(err)
			}

			conn, err := net.DialUDP("udp", nil, addr)
			if err != nil {
				panic(err)
			}

			_, err = conn.Write([]byte(m))
			if err != nil {
				panic(err)
			}

			udp++
		}

		os.Exit(0)
	}

	for i := 0; i < c; i++ {
		go func() {
			a1, err := net.ResolveTCPAddr("tcp", ":3000")
			if err != nil {
				panic(err)
			}
			c1, err := net.DialTCP("tcp", nil, a1)
			if err != nil {
				panic(err)
			}

			_, err = c1.Write([]byte(m))
			if err != nil {
				panic(err)
			}

			buf := make([]byte, 24)

			n, err := c1.Read(buf)
			if err != nil {
				panic(err)
			}

			if string(buf[:n]) != "pong" {
				panic(1)
			}

			err = c1.Close()
			if err != nil {
				panic(err)
			}

			g := atomic.AddInt64(&tcp, 1)

			if g%100 == 0 {
				fmt.Println("tcp", g)

				time.Sleep(time.Millisecond * 1000)
			}
		}()

		go func() {
			a2, err := net.ResolveUDPAddr("udp", ":3000")
			if err != nil {
				panic(err)
			}
			c2, err := net.DialUDP("udp", nil, a2)
			if err != nil {
				panic(err)
			}

			_, err = c2.Write([]byte(m))
			if err != nil {
				panic(err)
			}

			buf := make([]byte, 24)

			n, err := c2.Read(buf)
			if err != nil {
				panic(err)
			}

			if string(buf[:n]) != "pong" {
				panic(1)
			}

			err = c2.Close()
			if err != nil {
				panic(err)
			}

			g := atomic.AddInt64(&udp, 1)

			if g%100 == 0 {
				fmt.Println("udp", g)

				time.Sleep(time.Millisecond * 1000)
			}
		}()
	}

	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt, syscall.SIGTERM)

	<-signals
}

我遇到了一个奇怪的问题:在许多连接上,不是所有的UDP请求都被发送或处理。

当我发送100或200个请求时,服务器和客户端都告诉我所有的请求都成功了,但是从1000开始,UDP请求的丢失率约为5%,对于服务器和客户端都是如此,但没有发生panic。

我知道UDP允许丢包,但是在本地主机上的请求中,5%的丢包率似乎是一个错误。

英文:

i wrote simple server and client for tcp and udp connection

package main
//server.go
import (
&quot;fmt&quot;
&quot;net&quot;
&quot;os&quot;
&quot;os/signal&quot;
&quot;syscall&quot;
)
func main() {
tcp := 0
udp := 0
defer func(o, t *int) {
fmt.Println(*o, *t)
}(&amp;tcp, &amp;udp)
go func() {
l, err := net.ListenTCP(&quot;tcp&quot;, &amp;net.TCPAddr{
IP:   net.ParseIP(&quot;0.0.0.0&quot;),
Port: 3000,
})
if err != nil {
panic(err)
}
b := make([]byte, 24)
for {
conn, err := l.Accept()
if err != nil {
continue
}
n, err := conn.Read(b)
if err != nil {
continue
}
r := string(b[:n])
if r == &quot;close&quot; {
conn.Close()
break
} else {
_, err = conn.Write([]byte(&quot;pong&quot;))
if err != nil {
continue
}
}
conn.Close()
tcp++
}
l.Close()
}()
go func() {
conn, err := net.ListenUDP(&quot;udp&quot;, &amp;net.UDPAddr{
IP:   net.ParseIP(&quot;0.0.0.0&quot;),
Port: 3000,
})
if err != nil {
panic(err)
}
b := make([]byte, 24)
for {
n, addr, err := conn.ReadFromUDP(b)
if err != nil {
continue
}
r := string(b[:n])
if r == &quot;close&quot; {
break
} else {
_, err = conn.WriteToUDP([]byte(&quot;pong&quot;), addr)
if err != nil {
continue
}
}
udp++
}
conn.Close()
}()
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
&lt;-signals
}
package main
//client.go
import (
&quot;fmt&quot;
&quot;net&quot;
&quot;os&quot;
&quot;os/signal&quot;
&quot;strconv&quot;
&quot;sync/atomic&quot;
&quot;syscall&quot;
&quot;time&quot;
)
func main() {
t := &quot;tcp&quot;
m := &quot;ping&quot;
c := 1
if len(os.Args) &gt; 1 {
t = os.Args[1]
}
if len(os.Args) &gt; 2 {
m = os.Args[2]
}
if len(os.Args) &gt; 3 {
c, _ = strconv.Atoi(os.Args[3])
}
tcp := int64(0)
udp := int64(0)
defer func(o, t *int64) {
fmt.Println(*o, *t)
}(&amp;tcp, &amp;udp)
if c == 1 {
if t == &quot;tcp&quot; {
addr, err := net.ResolveTCPAddr(&quot;tcp&quot;, &quot;:3000&quot;)
if err != nil {
panic(err)
}
conn, err := net.DialTCP(&quot;tcp&quot;, nil, addr)
if err != nil {
panic(err)
}
_, err = conn.Write([]byte(m))
if err != nil {
panic(err)
}
tcp++
}
if t == &quot;udp&quot; {
addr, err := net.ResolveUDPAddr(&quot;udp&quot;, &quot;:3000&quot;)
if err != nil {
panic(err)
}
conn, err := net.DialUDP(&quot;udp&quot;, nil, addr)
if err != nil {
panic(err)
}
_, err = conn.Write([]byte(m))
if err != nil {
panic(err)
}
udp++
}
os.Exit(0)
}
for i := 0; i &lt; c; i++ {
go func() {
a1, err := net.ResolveTCPAddr(&quot;tcp&quot;, &quot;:3000&quot;)
if err != nil {
panic(err)
}
c1, err := net.DialTCP(&quot;tcp&quot;, nil, a1)
if err != nil {
panic(err)
}
_, err = c1.Write([]byte(m))
if err != nil {
panic(err)
}
buf := make([]byte, 24)
n, err := c1.Read(buf)
if err != nil {
panic(err)
}
if string(buf[:n]) != &quot;pong&quot; {
panic(1)
}
err = c1.Close()
if err != nil {
panic(err)
}
g := atomic.AddInt64(&amp;tcp, 1)
if g % 100 == 0 {
fmt.Println(&quot;tcp&quot;, g)
time.Sleep(time.Millisecond * 1000)
}
}()
go func() {
a2, err := net.ResolveUDPAddr(&quot;udp&quot;, &quot;:3000&quot;)
if err != nil {
panic(err)
}
c2, err := net.DialUDP(&quot;udp&quot;, nil, a2)
if err != nil {
panic(err)
}
_, err = c2.Write([]byte(m))
if err != nil {
panic(err)
}
buf := make([]byte, 24)
n, err := c2.Read(buf)
if err != nil {
panic(err)
}
if string(buf[:n]) != &quot;pong&quot; {
panic(1)
}
err = c2.Close()
if err != nil {
panic(err)
}
g := atomic.AddInt64(&amp;udp, 1)
if g % 100 == 0 {
fmt.Println(&quot;udp&quot;, g)
time.Sleep(time.Millisecond * 1000)
}
}()
}
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
&lt;-signals
}

and get a strange behavior: not all udp requests are sent or handled on many connections.

When i sent 100 or 200 both server and client tells me that all requests worked but from 1000 there is a strange ~5% requests loss on udp for both server and client but no panic.
I know udp allows packet loss but 5% on localhost requests seems like an error.

答案1

得分: 0

我们知道,UDP是无连接的,因此数据包丢失可能是由于UDP的这种特性引起的。有几种方法可以降低数据包丢失的速率。

  • 在客户端降低数据包发送速率
  • 在客户端调用SetWriteBuffer来增加缓冲区大小,并在服务器端设置SetReadBuffer来增加缓冲区大小
    conn, err := net.DialUDP("udp", nil, addr)

    err = conn.SetWriteBuffer(64 * 1024 * 1024)
  • 通过netstat -s -udp检查系统网络信息并获取UDP统计信息。您可以尝试更改服务器端的rmem_maxrmem_default的默认值。更多详细信息,请参考12
英文:

As we know, the UDP is connectionless, so packet loss may be caused by this nature of UDP. There could be several ways to lower the rate of packet loss.

  • Slow down the rate of packets sent on the client side
  • Call SetWriteBuffer to increase the buffer size on the client side and set SetReadBuffer to increase the buffer size on the server side
    conn, err := net.DialUDP(&quot;udp&quot;, nil, addr)

    err = conn.SetWriteBuffer(64 * 1024 * 1024)
  • Check the system network information through netstat -s -udp and get UDP statistics information. You could try to change the default value of rmem_max and rmem_default on the server side. For more details, please refer to 1 and 2

huangapple
  • 本文由 发表于 2022年10月27日 22:43:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/74223962.html
匿名

发表评论

匿名网友

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

确定