如何从用GoLang创建的TCP服务器中测量通过使用GoLang创建的TCP客户端的RTT/延迟?

4

我正在通过GoLang托管一个TCP服务器,然后我想使用多个TCP客户端连接到我的TCP服务器,并在每次连接新客户端时测量RTT。 我没有找到任何允许我在Golang中测量与此服务器连接的RTT的内容(例如我连接到本地主机,它不起作用)。 以下是我的TCP服务器代码。

package main

import (
    "bufio"
    "fmt"
    "log"
    "math/rand"
    "net"
    "os"
    "strconv"
    "strings"
    "time"
)

var counter int

const MIN = 1
const MAX = 100

func random() int {
    return rand.Intn(MAX-MIN) + MIN
}

func verifyPortNo(portNo string) bool {

    conn, err := net.Listen("tcp", portNo)
    if err != nil {
        log.Println("Connection error: ", err)
        log.Println("Cannot verify port")
        return false
    }

    log.Println("Available")
    conn.Close()
    return true
}

func handleConnection(con net.Conn, counter int) {
    fmt.Printf("Client %d: %s\n", counter, con.LocalAddr().String())
    defer con.Close()
    for {
        clientRequest, err := bufio.NewReader(con).ReadString('\n')
        if err != nil {
            fmt.Println(err)
            return
        }

        stop := strings.TrimSpace(clientRequest)
        if stop == "STOP" {
            break
        }
        result := strconv.Itoa(random()) + "\n"
        con.Write([]byte(string(result)))
    }
}

func main() {
    arguments := os.Args //first element of the argument array is the program name
    if len(arguments) == 1 {
        fmt.Println("Please provide a port number")
        return
    }

    PortNo := "localhost:" + arguments[1]
    fmt.Println(PortNo)
    if !verifyPortNo(PortNo) {
        return
    }
    n, err := net.Listen("tcp", PortNo)
    if err != nil {
        fmt.Println(err)
        return
    }

    //close the listener when the application closes
    defer n.Close()

    rand.Seed(time.Now().Unix())

    for {
        //while loop for TCP server to accept connections
        conn, err := n.Accept()
        if err != nil {
            fmt.Println(err)
            return
        }
        counter++
        go handleConnection(conn, counter)
    }

}

以下是我的TCP客户端代码。
package main

import (
    "bufio"
    "log"
    "net"
    "os"
    "strings"
    "time"
)

var counter int

func main() {
    for {
        go createTCPClient()
        time.Sleep(1 * time.Second)
    }

    // log.Println("Available")
    //netstat -anp TCP | grep 9999
}

func createTCPClient() {
    PortNo := "localhost:" + os.Args[1]

    conn, err := net.Dial("tcp", PortNo)
    if err != nil {
        log.Println("Connection error: ", err)
        log.Println("Cannot verify port")
        return
    }
    defer conn.Close()

    serverReader := bufio.NewReader(conn)
    for {
        reply, err := serverReader.ReadString('\n')
        if err != nil {
            println("Write to server failed:", err.Error())
            os.Exit(1)
        }
        println("reply from server=", strings.TrimSpace(reply))
    }

}

代码可以正常运行(见下图),但我无法理解如何测量每个TCP客户端的RTT并显示它。

查看图片描述


也许这个可以帮到你 https://github.com/grahamking/latency/blob/07ba2b7cc2210227cdb9afbec07e65fcfcd2c968/latency.go#L99 - Tiago Peczenyj
是的,我尝试过了,但不幸的是,我找不到连接到刚刚运行的TCP服务器的方法。不过还是谢谢你。 - zahid kamil
1个回答

5

唯一的可移植解决方案是使用/设计一个应用程序协议,让您确定往返时间(RTT)。例如,在请求/响应之间计算时间差。

另外,操作系统内核通常记录TCP连接延迟。然而:

  • 没有可移植的方法来检索TCP RTT
  • TCP RTT不在所有平台上都可用。

此简化示例演示了如何在Linux下读取包含TCP RTT的TCPInfo:

//go:build linux

package main

import (
    "fmt"
    "net"
    "time"

    "golang.org/x/sys/unix"
)

func main() {
    listener, err := net.Listen("tcp", ":0")
    check(err)

    fmt.Println("Listening on", listener.Addr())

    for {
        conn, err := listener.Accept()
        check(err)
        go func(conn *net.TCPConn) {
            defer conn.Close()
            info, err := tcpInfo(conn)
            check(err)
            rtt := time.Duration(info.Rtt) * time.Microsecond
            fmt.Println(rtt)
        }(conn.(*net.TCPConn))
    }
}

func tcpInfo(conn *net.TCPConn) (*unix.TCPInfo, error) {
    raw, err := conn.SyscallConn()
    if err != nil {
        return nil, err
    }

    var info *unix.TCPInfo
    ctrlErr := raw.Control(func(fd uintptr) {
        info, err = unix.GetsockoptTCPInfo(int(fd), unix.IPPROTO_TCP, unix.TCP_INFO)
    })
    switch {
    case ctrlErr != nil:
        return nil, ctrlErr
    case err != nil:
        return nil, err
    }
    return info, nil
}

func check(err error) {
    if err != nil {
        panic(err)
    }
}

本地连接示例输出:

$ ./tcpinfo 
Listening on [::]:34761
97µs
69µs
103µs
60µs
92µs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接