Go:服务器应该在接收到客户端的消息之前阻塞。

huangapple go评论79阅读模式
英文:

Go: Server should block until a message from the client is received

问题

我正在使用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 // 用于模拟网络连接

	enc := gob.NewEncoder(&network) // 将写入网络
	dec := gob.NewDecoder(&network) // 将从网络读取

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

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

	var m Message
	err = dec.Decode(&m) // 接收消息

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

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

这个示例可以正常工作,但我希望服务器在接收到新消息之前阻塞,这样我就可以将接收过程放在无限循环goroutine中。

类似于以下代码:

for {
    // 服务器在此处阻塞,直到接收到来自客户端的消息

    fmt.Println("Received message:")

    // 解码新消息
    var m Message
	err = dec.Decode(&m) // 接收消息

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

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

I'm building some server/client application in Go (the language is new to me). I searched a lot and read a whole bunch of different examples but there is still one thing I can't find. Lets say I have a single server client up and running. The client will send some kind of a message to the server and vice versa. Encoding and decoding is done by the package gob.

This example is not my application, it is only a quick example:

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

This works fine, but I want the server to block until a new message is received so I can put the receiving process inside a infinite for loop inside a goroutine.

Something like that:

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

答案1

得分: 2

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

在playground上的工作示例

英文:

The gob decoder blocks until it has read a full message or there's an error. The read loop in the question works as is.

working example on the playground

答案2

得分: 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
}
// 在这里对`buf`进行解码(使用gob解码)

你可能知道客户端的实现可以参考服务器端的源代码。

英文:

add a length header to the raw tcp stream.

that means, send a 4-bytes-length-header information to server before send the real load. and in server side read 4 bytes, allocate buffer, full read total message, and finally decode.

assume you have a tcp connection conn, in server side we could have:

func getInt(v []byte) int {
	var r uint
	r = 0
	r |= uint(v[0]) &lt;&lt; 24
	r |= uint(v[1]) &lt;&lt; 16
	r |= uint(v[2]) &lt;&lt; 8
	r |= uint(v[3]) &lt;&lt; 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

you may know client side refer the the server side source I think.

huangapple
  • 本文由 发表于 2015年12月28日 17:38:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/34491011.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定