Go:服务器应该阻塞,直到收到来自客户端的消息

时间:2015-12-28 09:38:18

标签: go server client

我正在Go构建一些服务器/客户端应用程序(这种语言对我来说是新的)。我经常搜索并阅读了大量不同的例子,但仍有一件事我无法找到。假设我有一台服务器客户端启动并运行。客户端将向服务器发送某种消息,反之亦然。编码和解码由包gob完成。

这个例子我的应用程序,它只是一个简单的例子:

package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
)

type Message struct {
    Sender   string
    Receiver string
    Command  uint8
    Value    int64
}

func (message *Message) Set(sender string, receiver string, command uint8, value int64) *Message {

    message.Sender = sender
    message.Receiver = receiver
    message.Command = command
    message.Value = value

    return message
}

func main() {

    var network bytes.Buffer // Stand-in for a network connection

    enc := gob.NewEncoder(&network) // Will write to network.
    dec := gob.NewDecoder(&network) // Will read from network.

    message := new(Message).Set("first", "second", 10, -1)

    err := enc.Encode(*message) // send message
    if err != nil {
        log.Fatal("encode error:", err)
    }

    var m Message
    err = dec.Decode(&m) // receice message

    if err != nil {
        log.Fatal("decode error:", err)
    }

    fmt.Printf("%q %q %d %d\n", m.Sender, m.Receiver, m.Command, m.Value)
}

这样可以正常工作,但我希望服务器在收到新邮件之前阻止,这样我就可以将接收流程放在infinite for loop内的goroutine内。

类似的东西:

for {
    // The server blocks HERE until a message from the client is received

    fmt.Println("Received message:")

    // Decode the new message
    var m Message
    err = dec.Decode(&m) // receice message

    if err != nil {
        log.Fatal("decode error:", err)
    }

    fmt.Printf("%q %q %d %d\n", m.Sender, m.Receiver, m.Command, m.Value)
}

2 个答案:

答案 0 :(得分:2)

gob解码器阻塞,直到它读取完整的消息或出现错误。问题中的读取循环按原样工作。

working example on the playground

答案 1 :(得分:0)

为原始tcp流添加长度标头。

这意味着,在发送实际负载之前,将4字节长度的头信息发送到服务器。在服务器端读取4个字节,分配缓冲区,完全读取总消息,最后解码。

假设您有一个tcp连接conn,在服务器端我们可以:

func getInt(v []byte) int {
    var r uint
    r = 0
    r |= uint(v[0]) << 24
    r |= uint(v[1]) << 16
    r |= uint(v[2]) << 8
    r |= uint(v[3]) << 0
    return int(r)
}

buf := make([]byte, 4)
_, err := io.ReadFull(conn, buf)
if err != nil {
    return
}

length := getInt(buf)
buf = make([]byte, length)
_, err = io.ReadFull(conn, buf)
if err != nil {
    return
}
//do gob decode from `buf` here

您可能知道客户端参考我认为的服务器端源。