简体   繁体   中英

Consecutive Encode/Decode using GOB

I am new to programming Golang Sockets. When I try to send one message from client to server, it is working perfectly. However, when I try to send 10 consecutive messages, I get an error. Any clues/keywords to search for. Please find enclosed a sample code.

Server.go

package main

import (
    "encoding/gob"
    "fmt"
    "net"
    "os"
)

func main() {
    tcpAddr, err := net.ResolveTCPAddr("tcp4", ":5555")
    checkError("ResolveTCPAddr", err)

    listener, err := net.ListenTCP("tcp", tcpAddr)
    checkError("ListenTCP", err)
    conn, err := listener.Accept()
    checkError("Accept", err)

    for i := 0; i < 10; i++ {

        var s string
        dec := gob.NewDecoder(conn)
        err = dec.Decode(&s)
        checkError("Decode", err)
        fmt.Println(s)
    }
}

func checkError(info string, err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, info+": Run - Fatal error: %s\n", err.Error())
        os.Exit(1)
    }
}

Client.go

package main

import (
    "encoding/gob"
    "fmt"
    "net"
    "os"
)

func main() {
    tcpAddr, err := net.ResolveTCPAddr("tcp4", ":5555")
    checkError("ResolveTCPAddr", err)

    conn, err := net.DialTCP("tcp", nil, tcpAddr)
    checkError("DialTCP", err)

    for i := 0; i < 10; i++ {
        enc := gob.NewEncoder(conn)
        err = enc.Encode("test")
        checkError("Encode", err)
    }
}

func checkError(info string, err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, info+": Run - Fatal error: %s\n", err.Error())
        os.Exit(1)
    }
}

SCREEN:

test
test
test
test
test
Decode: Run - Fatal error: EOF
exit status 1

The problem is that a decoder buffers data from the underlying reader and that buffered data can include data from a later message in the stream. The buffered data is discarded when the application discards the decoder. A later decoder returns an error because it is reading an incomplete message.

There's an easy fix to this problem. The gob package is designed to read and write streams of values. Create the encoder and decoder outside of the loop and let the package handle the message framing.

enc := gob.NewEncoder(conn)
for i := 0; i < 10; i++ {
    err = enc.Encode("test")
    checkError("Encode", err)
}


dec := gob.NewDecoder(conn)
for i := 0; i < 10; i++ {
    var s string
    err = dec.Decode(&s)
    checkError("Decode", err)
    fmt.Println(s)
}

If for some reason you must create the encoder and decoder inside the loop, then the application must implement message framing to prevent the decoder from reading more than a single value. One way to frame the messages is to have the client write a length prefix before the gob encoded value. The server reads the length and then limits the decoder to reading that number of bytes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM