连续 Encode/Decode 使用 GOB

Consecutive Encode/Decode using GOB

我是 Golang 套接字编程的新手。当我尝试从客户端向服务器发送一条消息时,它运行良好。但是,当我尝试连续发送 10 条消息时,出现错误。要搜索的任何 clues/keywords。请查找随附的示例代码。

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)
    }
}

屏幕:

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

问题在于解码器会缓冲来自底层 reader 的数据,并且缓冲的数据可能包含来自流中稍后消息的数据。当应用程序丢弃解码器时,缓冲数据将被丢弃。后来的解码器 returns 出错,因为它正在读取不完整的消息。

这个问题有一个简单的解决方法。 gob 包旨在读取和写入值流。在循环外创建编码器和解码器,让包处理消息框架。

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)
}

如果出于某种原因必须在循环内创建编码器和解码器,则应用程序必须实施消息框架以防止解码器读取多个值。构建消息的一种方法是让客户端在 gob 编码值之前写入一个长度前缀。服务器读取长度,然后限制解码器读取该字节数。