2

I'm trying to figure out how to serialize a struct and send it via UDP to my server. I managed to actually send the struct but upon receiving I do not have any values in it... Except when I statically add a number.

In the following code I am sending a UDP packet to port 8080 with a sequential number which are just the numbers from 0-9. I'm adding + 1 to it to show my point. What I expect is that on the receiving end I should receive in the message part 1-10. But the only thing I receive is the number 1 which means that the variable should be set to 0.

To verify if I actually send 0 I print the length of the buffer I receive and it is the correct length of what it should be. So I must be doing something wrong with the decoding.

send function:

func send_udp() {
    dst, _ := net.ResolveUDPAddr("udp", "localhost:8080")
    conn, _ := net.ListenPacket("udp", ":0")
    defer conn.Close()

    var buf bytes.Buffer
    encoder := gob.NewEncoder(&buf)
    for n := 0; n < 10; n++ {
        var msg int64 = int64(n) + 1
        packet := &Packet{[]int{5}, msg}
        encoder.Encode(packet)
        conn.WriteTo(buf.Bytes(), dst)
    }
}

The listen function:

func listen_udp() {
    dst, _ := net.ResolveUDPAddr("udp", "localhost:8080")
    conn, _ := net.ListenUDP("udp", dst)
    defer conn.Close()

    for {
        buf := make([]byte, 4096)
        n, _, _ := conn.ReadFromUDP(buf[:])
        fmt.Println(n)
        dec := gob.NewDecoder(bytes.NewReader(buf[:n]))
        p := Packet{}
        dec.Decode(&p)
        if len(p.Parts) != 0 {
            fmt.Printf("Received: %+v\n", p)
        }
    }
}

the struct I'm trying to send:

type Packet struct {
    Parts   []int 
    Message int64 
}
Fabio Oesch
  • 143
  • 2
  • 11
  • 2
    You're ignoring all the error values in the example (writing, reading, encoding, decoding, etc); have you checked them for clues? (there's also no reason to use `[:]` here, I'm not sure what you think that's doing) – JimB Nov 15 '18 at 18:09
  • `[:]` is useful in python to copy the slice. In python, when you slice an array, it first copies everything. In go, each slice still references the original array and therefore buys you nothing. – poy Nov 15 '18 at 21:37

1 Answers1

1

Implemented this on my local machine. Yes PLEASE check your errors, but lucky for you, nothing was returning any. Here is what I did to fix the problem. In send_udp initialize the Buffer and Encoder INSIDE the for loop.

func send_udp() error {
    dst, err := net.ResolveUDPAddr("udp", "localhost:8080")
    if err != nil {
        return err
    }
    conn, err := net.ListenPacket("udp", ":0")
    if err != nil {
        return err
    }
    defer conn.Close()

    for n := 0; n < 10; n++ {
        // inside for loop
        var buf bytes.Buffer
        encoder := gob.NewEncoder(&buf)

        var msg int64 = int64(n) + 1
        packet := &Packet{[]int{5}, msg}
        err = encoder.Encode(packet)
        if err != nil {
            return err
        }
        _, err = conn.WriteTo(buf.Bytes(), dst)
        if err != nil {
            return err
        }
    }
    return nil
}

Note that declaring the Buffer outside the for loop, you were actually sending every previous Packet each time you added a new one, hence the increasing n values when you printed the return from ReadFromUDP in your listen_udp function, but it was only decoding the first one every time. So if you were meaning to send them all at once, you would have to loop over the Decoder in your listen_udp function.

RayfenWindspear
  • 6,116
  • 1
  • 30
  • 42
  • Sorry for scarying everyone. I do have error checking in my code but I did not post it here because I thought it was not relevant to the code. I will remember to keep the error checking in the code next time I ask a question. Thank you for the easy fix. – Fabio Oesch Nov 15 '18 at 21:47
  • @FabioOesch: another option is to annotate your sample code with comments like `// NOTE: error checking code here` so that the community knows you're checking them but without cluttering the code from its intent. – maerics Nov 15 '18 at 22:08
  • @FabioOesch or just do the post with a pretend error check function like `check(err)` then just leave out that function because it's irrelevant. Anyone wanting to implement your code could then just write a simple function that panics if err isn't nil. Makes it easier for people willing to do so to get your MVP up and running to test it. – RayfenWindspear Nov 15 '18 at 22:18