接收可以部分写入的 protobuf 编码消息?

我正在尝试通过 TCP 在 GoLang 中发送和接收 protobuff 编码的消息,发送方可以write()在操作中途取消,接收方可以正确接收部分消息。


请注意,我使用单个 TCP 连接无限发送不同用户定义类型的消息(这不是每个连接消息的情况)


为了具体解释我的问题,首先我将介绍如何在没有部分写入的情况下实现发送/接收。


在我的程序中,有多种类型的消息,定义在一个.proto文件中。我将解释一种这样的消息类型的机制。


message MessageType {

  int64 sender = 1;

  int64 receiver = 2;

  int64 operation = 3;

  string message = 4;

}

然后我使用 Golang Protobuf 插件生成存根。


然后在发送方,下面是我发送的方式。


func send(w *bufio.Writer, code uint8, oriMsg MessageType) {

    err := w.WriteByte(code)

    data, err := proto.Marshal(oriMsg)

    lengthWritten := len(data)

    var b [8]byte

    bs := b[:8]

    binary.LittleEndian.PutUint64(bs, uint64(lengthWritten))

    _, err = w.Write(bs)

    _, err = w.Write(data)

    w.flush()

}

然后在receiver端,下面是我的接收方式。


reader *bufio.Reader

for true {

        if msgType, err = reader.ReadByte(); err != nil {

            panic()

        }

        if msgType == 1 || msgType == 2{

            var b [8]byte

            bs := b[:8]


            _, err := io.ReadFull(reader, bs) 

            numBytes := binary.LittleEndian.Uint64(bs)

            data := make([]byte, numBytes)

            length, err := io.ReadFull(reader, data) 

            msg *MessageType = new(GenericConsensus) // an empty message 

            err = proto.Unmarshal(data[:length], msg) 

            // do something with the message 

            

        } else {

            // unknown message type handler

        }

    }

现在我的问题是,如果发件人在中间中止他的写入怎么办:更具体地说,


情况 1:如果发送方写入消息类型字节,然后中止怎么办?在这种情况下,接收方将读取消息类型字节,并等待接收 8 字节的消息长度,但发送方不发送它。


情况 2:这是情况 1 的扩展版本,其中发送方首先仅发送消息类型字节,中止发送消息长度和编组消息,然后发送下一条消息:类型字节、长度和编码消息。现在在接收方,一切都出错了,因为违反了消息的顺序(类型、长度和编码消息)。


所以我的问题是,如何修改接收方,使其在发送方违反预先约定的 type:length:encoded-message 顺序的情况下仍能继续运行?


慕森卡
浏览 72回答 1
1回答

慕少森

为什么发件人会中止一条消息,然后发送另一条消息?你的意思是它是一个完全拜占庭式的发件人?还是您正在准备进行模糊测试?如果您的 API 合同规定发送方始终需要发送正确的消息,那么接收方可以简单地忽略错误消息,甚至可以在发现违反 API 合同的情况下关闭连接。如果你真的需要它,这里有一些关于如何让它工作的想法:从一个独特的序言开始——但是你必须确保这个序言永远不会出现在数据中在将消息发送到解码器之前向消息添加校验和。所以完整的数据包将是[msg_type : msg_len : msg : chksum ]:这允许接收方检查它是正确的消息还是格式错误的消息。此外,就目前的代码而言,发送最大 64 位的大小很容易导致崩溃。所以你还应该检查大小是否在一个有用的范围内。我会将其限制为 32 位...
打开App,查看更多内容
随时随地看视频慕课网APP