2

I'm having issues with the gob protocol (or maybe networking in general, where my knowledge is weak), and I don't understand why the following code does not work properly. It is just supposed to be a simple example of maintaining an open TCP connection, and sending multiple gobs through it. The code will send, and receive, but often corrupts its data. Thank you in advance.

package main

import (
    "encoding/gob"
    "fmt"
    "net"
    "strconv"
    "time"
)

type Message struct {
    Msg string
}

func main() {
    gob.Register(new(Message))

    clientAddr, err := net.ResolveTCPAddr("tcp", "localhost:12346")
    if err != nil {
        fmt.Println(err)
    }
    serverAddr, err := net.ResolveTCPAddr("tcp", "localhost:12345")
    if err != nil {
        fmt.Println(err)
    }

    serverListener, err := net.ListenTCP("tcp", serverAddr)
    if err != nil {
        fmt.Println(err)
    }
    conn, err := net.DialTCP("tcp", clientAddr, serverAddr)
    if err != nil {
        fmt.Println(err)
    }
    serverConn, err := serverListener.AcceptTCP()
    if err != nil {
        fmt.Println(err)
    }
    done := false
    go func() {
        for !done {
            recieveMessage(serverConn)
        }
    }()
    for i := 1; i < 1000; i++ {
        sent := Message{strconv.Itoa(i)}
        sendMessage(sent, conn)
    }
    time.Sleep(time.Second)
    done = true
}

func sendMessage(msg Message, conn *net.TCPConn) {
    enc := gob.NewEncoder(conn)
    err := enc.Encode(msg)
    if err != nil {
        fmt.Println(err)
    }
}

func recieveMessage(conn *net.TCPConn) {
    msg := new(Message)
    dec := gob.NewDecoder(conn) // Will read from network.
    err := dec.Decode(msg)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println("Client recieved:", msg.Msg)
}
Qubert
  • 185
  • 3
  • 9
  • Corrupts its data *in what way*? How often is "often"? – Adrian Jun 22 '17 at 17:05
  • The output of the example was once:gob: unknown type id or corrupted data Client recieved: Client recieved: 979 Client recieved: 981 gob: unknown type id or corrupted data Client recieved: gob: unknown type id or corrupted data Client recieved: ... – Qubert Jun 22 '17 at 17:08
  • The example is locally executable (run it and see for yourself) :) – Qubert Jun 22 '17 at 17:09
  • I asked because presumably you've already run it and have the information - if you want help from the community, it's best to include as much detail as possible rather than expecting others to do the work. – Adrian Jun 22 '17 at 17:11
  • Fair enough (I should have made a playground link myself, but @Cerise-Limón already has one fixed up.) – Qubert Jun 22 '17 at 17:19

1 Answers1

3

The problem is that the decoder can buffer data from the next message. When this happens, the next new decoder starts in the middle of a message. The fix is to use a single encoder and decoder.

func main() {
    ...
    dec := gob.NewDecoder(conn) // Will read from network.
    enc := gob.NewEncoder(serverConn)
    go func() {
        for !done {
            recieveMessage(dec)
        }
    }()

    for i := 1; i < 1000; i++ {
        sent := Message{strconv.Itoa(i)}
        sendMessage(sent, enc)
    }
    ...
}

func sendMessage(msg Message, enc *gob.Encoder) {
    err := enc.Encode(msg)
    if err != nil {
        fmt.Println(err)
    }
}

func recieveMessage(dec *gob.Decoder) {
    msg := new(Message)
    err := dec.Decode(msg)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println("Client recieved:", msg.Msg)
}

Run it in the playground

Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
  • great example. one more question , how to detect that the gob message is coming fresh new on the server side, when the client halt a while than send a new message(gob) – temple Apr 03 '18 at 14:45