Search code examples
dockergoconcurrencyudprouter

How to measure RTT/Latency in a concurrent UDP server and clients created in GoLang?


I was able to run a concurrent UDP server and connect UDP clients to this concurrent server. However, I would like to know how to measure the latency of this UDP server.

For some reason, Netcat commands in Linux do not work and they work well with TCP. I can't seem to measure it because I am hosting this server on my machine and I am trying to measure the latency. Additionally, a lot of UDP clients can connect to the UDP server concurrently, there seems to be a very high limit.

Should I instead create a docker container and run it on a router and then measure the latency to the router? How would you proceed with this?

Below is the code for the UDP Web server:

package main

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

func random(min, max int) int {
    return rand.Intn(max-min) + min
}

func main() {
    arguments := os.Args
    if len(arguments) == 1 {
        fmt.Println("Please provide a port number!")
        return
    }
    PORT := ":" + arguments[1]

    s, err := net.ResolveUDPAddr("udp4", PORT)
    if err != nil {
        fmt.Println(err)
        return
    }

    connection, err := net.ListenUDP("udp4", s)
    if err != nil {
        fmt.Println(err)
        return
    }

    defer connection.Close()
    buffer := make([]byte, 1024)
    rand.Seed(time.Now().Unix())

    for {
        n, addr, err := connection.ReadFromUDP(buffer)
        go func() {
            fmt.Print("-> ", string(buffer[0:n-1]))
            fmt.Println(addr.String())
            if strings.TrimSpace(string(buffer[0:n])) == "STOP" {
                fmt.Println("Exiting UDP server!")
                return
            }

            data := []byte(strconv.Itoa(random(1, 1001)))
            fmt.Printf("data: %s\n", string(data))
            _, err = connection.WriteToUDP(data, addr)
            if err != nil {
                fmt.Println(err)
                return
            }
        }()
    }
}

Below is the code for the UDP clients:

package main

import (
    "fmt"
    "net"
    "os"
    "time"
)

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

func main() {
    arguments := os.Args
    if len(arguments) == 1 {
        fmt.Println("Please provide a host:port string")
        return
    }
    CONNECT := arguments[1]

    s, err := net.ResolveUDPAddr("udp4", CONNECT)
    check(err)
    c, err := net.DialUDP("udp4", nil, s)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Printf("The UDP server is %s\n", c.RemoteAddr().String())
    defer c.Close()

    for {
        time.Sleep(1 * time.Second)
        go func() {
            text := []byte("heyyyy")
            _, err := c.Write(text)
            if err != nil {
                fmt.Println(err)
                return
            }

            buffer := make([]byte, 1024)
            n, _, err := c.ReadFromUDP(buffer)
            if err != nil {
                fmt.Println(err)
                return
            }
            fmt.Printf("Reply: %s\n", string(buffer[0:n]))

        }()

    }
}

Solution

  • I was able to run a concurrent UDP server and connect UDP clients to this concurrent server. However, I would like to know how to measure the latency of this UDP server.

    In order to measure one-way latency you will need to send a timestamp in the UDP segment payload and then check the elapsed time in the receiver.

    To get the RTT latency, you can send the timestamp in the payload, make the receiver to bounce the packet back, receive it at the sender and then finally check the elapsed time.

    Measuring one-way latency across network would be hard since you would need high accurately synchronized clocks in the sender host and the receiver host. Hence across networks, usually people measure only jitter and RTT latency, not one-way latency.

    For some reason, Netcat commands in Linux do not work and they work well with TCP.

    netcat does work well with UDP. Maybe you missed the -u switch?

    $ nc -l -u -p 8080 &
    [1] 2171
    $ echo hi | nc -u localhost 8080
    hi
    

    I can't seem to measure it because I am hosting this server on my machine and I am trying to measure the latency. Additionally, a lot of UDP clients can connect to the UDP server concurrently, there seems to be a very high limit.

    Just for the sake of accurate terminology, UDP is a connectionless protocol, so we usually don't speak of connecting with UDP, but speak of just sending and receiving datagrams.