使用原始tcp时,确保传递整个消息的好方法是什么?

时间:2015-09-04 13:58:25

标签: json node.js tcp go buffer

假设我有一个应用程序,在后端我想使用原始tcp,以便我可以在不同的服务之间进行双向通信。在这个应用程序中,我希望通过一个由json对象组成的有效负载发送,当发送json数据时,每隔几条消息,它就会被切断,剩下的就会聚集到下一个响应中。由于从http升级所用的时间,我不想使用像websockets这样的东西。确保json对象来自一个节点并从另一个节点读取为整个 json对象的好方法(并且希望是最好的)是什么?

我知道发送和接收设置大小的缓冲区和心跳消息是经验法则,但我能看到一个例子吗?最好是在Javascript(node的net stdlib)或Golang(它是net stdlib),因为那些是我最熟练的语言,尽管我并不关心它最终用的是什么语言。

(我知道有几个问题在询问有关确保使用tcp传递消息的相似事项,但没有人要求我找到一个例子)

我知道tcp是一个流。我只想问一种方法来确保在将特定的json对象写入此流时,如何确保在另一端获得相同的json对象,如“从节点a发送json对象X,ok节点b收到同一个对象 X“

1 个答案:

答案 0 :(得分:4)

您不需要心跳或固定大小的消息来确认递送。如果您需要确保交付,则需要申请级别确认。如果您需要确保传递正确的消息,则需要包含唯一的消息ID以进行确认。如果您需要确保邮件未被更改,则需要包含校验和或MAC。

这听起来好像你在消息框架方面遇到了麻烦。虽然有很多方法来构建您的消息(简单的长度前缀,type-length-value,HTTP / 1.1等),但一个简单的解决方案是使用内置的json.Encoderjson.Decoder

示例客户端,发送" PING"消息每秒:

type Message struct {
    Payload string
}

func sendMessages(c net.Conn) {
    message := Message{}

    encoder := json.NewEncoder(c)

    for i := 0; ; i++ {
        message.Payload = fmt.Sprintf("PING %d", i)
        err := encoder.Encode(message)
        if err != nil {
            log.Fatal(err)
        }
        time.Sleep(time.Second)
    }
}

示例服务器:

type Message struct {
    Payload string
}

func receiveMessages(c net.Conn) {
    m := Message{}

    decoder := json.NewDecoder(c)
    for {
        err := decoder.Decode(&m)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("Received: %#v\n", m)
    }
}