登录
首页 >  Golang >  Go问答

go udp请求(数据包)丢失

来源:stackoverflow

时间:2024-02-11 21:00:26 180浏览 收藏

你在学习Golang相关的知识吗?本文《go udp请求(数据包)丢失》,主要介绍的内容就涉及到,如果你想提升自己的开发能力,就不要错过这篇文章,大家要知道编程理论基础和实战操作都是不可或缺的哦!

问题内容

我为 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%,但没有恐慌。

我知道 udp 允许丢包,但 localhost 请求上的 5% 似乎是一个错误。


正确答案


众所周知,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

终于介绍完啦!小伙伴们,这篇关于《go udp请求(数据包)丢失》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布Golang相关知识,快来关注吧!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>