OS and protobuf version

go1.18.1 linux/amd64,github.com/golang/protobuf v1.5.2.

Introduction

我试图使用递归原型定义.

.proto

message AsyncConsensus {
  int32 sender = 1;
  int32 receiver = 2;
  string unique_id = 3; // to specify the fall back block id to which the vote asyn is for
  int32 type = 4; // 1-propose, 2-vote, 3-timeout, 4-propose-async, 5-vote-async, 6-timeout-internal, 7-consensus-external-request, 8-consensus-external-response, 9-fallback-complete
  string note = 5;
  int32 v = 6 ; // view number
  int32 r = 7;// round number
  message Block {
    string id = 1;
    int32 v = 2 ; // view number
    int32 r = 3;// round number
    Block parent = 4;
    repeated int32 commands = 5;
    int32 level = 6; // for the fallback mode
  }
  Block blockHigh = 8;
  Block blockNew = 9;
  Block blockCommit = 10;
}

以下是我如何指挥和取消指挥

func (t *AsyncConsensus) Marshal(wire io.Writer) error {
    data, err := proto.Marshal(t)
    if err != nil {
        return err
    }
    lengthWritten := len(data)
    var b [8]byte
    bs := b[:8]
    binary.LittleEndian.PutUint64(bs, uint64(lengthWritten))
    _, err = wire.Write(bs)
    if err != nil {
        return err
    }
    _, err = wire.Write(data)
    if err != nil {
        return err
    }
    return nil
}

func (t *AsyncConsensus) Unmarshal(wire io.Reader) error {

    var b [8]byte
    bs := b[:8]
    _, err := io.ReadFull(wire, bs)
    if err != nil {
        return err
    }
    numBytes := binary.LittleEndian.Uint64(bs)
    data := make([]byte, numBytes)
    length, err := io.ReadFull(wire, data)
    if err != nil {
        return err
    }
    err = proto.Unmarshal(data[:length], t)
    if err != nil {
        return err
    }
    return nil
}

func (t *AsyncConsensus) New() Serializable {
    return new(AsyncConsensus)
}

My expected outcome

当通过TCP封送并发送到同一进程时,它应该正确解组并生成正确的数据 struct .

Resulting error

错误"cannot parse invalid wire-format data"

Additional information

我try 了非递归的.proto个定义,以前从未遇到过这个问题.

推荐答案

这不是Protobuff的bug,而是关于如何构造marshalunmarshal Protobuff的问题.

作为一个具体的指导原则,不要同时使用marshalunmarshal原型buff struct ,因为这会导致比赛条件.

在您提供的特定示例中,我看到了递归数据 struct ,因此,即使对marshalunmarshal的每次调用使用单独的 struct ,父对象中的指针也可能会导致共享指针.

使用深度复制技术删除任何依赖项,这样就不会遇到竞争条件.

func CloneMyStruct(orig *proto.AsyncConsensus_Block) (*proto.AsyncConsensus_Block, error) {
    origJSON, err := json.Marshal(orig)
    if err != nil {
        return nil, err
    }

    clone := proto.AsyncConsensus_Block{}
    if err = json.Unmarshal(origJSON, &clone); err != nil {
        return nil, err
    }

    return &clone, nil
}

Go相关问答推荐

具有GRPC的RBAC(基于角色的访问控制)-网关生成的REST风格的API

Golang Viper:如果第一个字段不存在,如何从另一个字段获取值

GORM Find方法中缺少字段

golang.org/x/oauth2 oauth2.Config.Endpoint.TokenURL mock:缺少access_token

如何使用工作区方法扩展克隆的Golang库

如何在S汇编器中更高效地将全局数据加载到霓虹灯寄存器?

Azure golang SDK - 将 AcrPull 角色分配给 AKS 群集

在VSCode中如何使用特定的文件名提供编译命令

整理时转换值

Go Colly 如何找到请求的元素?

为超时的单元测试创​​建 deadlineExceededError:true

在 Go 中读取数字行

转到文本/模板模板:如何根据模板本身的值数组判断值?

显示作为服务帐户身份验证的谷歌日历事件 - Golang App

如何使用golang操作很长的字符串以避免内存不足

go 堆栈跟踪:在某些函数调用参数或返回值之后的问题(?)标记是什么意思?

从 Go struct 中提取标签作为 reflect.Value

行之间的模板交替设计

如何解决在mac m1中运行gcc失败退出状态1?

Go 错误处理、类型断言和 net package包