Search code examples
goudpbufferbufferedreader

Buffered reader VS listenUDP


If I am "infinitely" using the buffered reader to wait for messages from the server, is this not pretty much the same as using ListenUDP?

But if use ListenUDP, then I've created another server ...

Is it bad practice to "infinitely" collect from this buffered reader or is that in general how it is done with the client?

client.go

package main

import (
    "fmt"
    "time"
    "net"
    "sync"
    "bufio"
)

func xyz(conn net.Conn, p []byte) {
    rd := bufio.NewReader(conn)
    for {
        fmt.Printf("line\n")
        _, err := rd.Read(p)
        if err == nil {
            fmt.Printf("SERVER : %s\n", p)
        } else {
            fmt.Printf("Some error %v\n", err)
        }
    }
}

func main() {
    var wg = &sync.WaitGroup{}
    p :=  make([]byte, 2048)
    conn, err := net.Dial("udp", "127.0.0.1:1234")
    if err != nil {
        fmt.Printf("Some error %v", err)
        return
    }
    wg.Add(1)
    go xyz(conn, p)
    time.Sleep(2 * time.Second);
    fmt.Fprintf(conn, "Give me a hash to work on ...")
    time.Sleep(4 * time.Second)
    wg.Wait()
}

server.go

package main

import (
    "fmt"
    "net"
)

func sendResponse(conn *net.UDPConn, addr *net.UDPAddr, hash string) {
    _,err := conn.WriteToUDP([]byte("Hello, here is the hash  - " + hash), addr)
    if err != nil {
        fmt.Printf("Couldn't send response %v", err)
    }
}

func main() {
    hash := "36";
    p := make([]byte, 2048)
    addr := net.UDPAddr{
        Port: 1234,
        IP: net.ParseIP("127.0.0.1"),
    }
    ser, err := net.ListenUDP("udp", &addr)
    if err != nil {
        fmt.Printf("Some error %v\n", err)
        return
    }
    for {
        _, remoteaddr, err := ser.ReadFromUDP(p)
        fmt.Printf("CLIENT : %v : %s\n", remoteaddr, p)
        if err !=  nil {
            fmt.Printf("Some error  %v", err)
            continue
        }
        go sendResponse(ser, remoteaddr, hash)
    }
}

Solution

  • You don't need to use a bufio.Reader to read from a net.Conn, and in the case of a UDP connection, it can only cause problems.

    UDP is not stream based, so you will always need to read each individual datagram. In the best case a bufio.Reader is just buffering the data one extra time, in the worst case the buffer is near full and you only get a partial read, losing data. You also can no longer differentiate the messages once multiple datagrams have been buffered unless they contain additional framing.

    Just read directly from the net.Conn into your []byte:

    for {
        n, err := conn.Read(p)
        fmt.Printf("SERVER : %s\n", p[:n])
        if err != nil {
            fmt.Printf("Some error %v\n", err)
            return
        }
    }