如何获取重复消息数据的内容 [英] How to access content of repeated message data

查看:12
本文介绍了如何获取重复消息数据的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要使用protocol buffer使用gRPC发送和接收以下类型

std:array<std::complex<int>, 2> bar_array;
  • 获得创意的来源:12

我到目前为止所做的工作

我的方法(我有意省略不必要的代码)
  • proto file
syntax = "proto3";

package expcmake;

message child_data {
    repeated int32 child_data_list = 1;
}

message Address {
    child_data child_data_var = 8;
    repeated child_data parent_data_list = 9;
}
  • server.cpp

    • 这里,首先我做了一个虚拟的std:array<std::complex<int>, 2>数据。然后,我用std::complex<int>数据填充了child_data_list。在每一次填充realimaginary部分之后,我将它们推入parent_data_list。另外,目前我有clearedchild_data_list
    • Client消息名称为NameQuerryServer消息名称为Address
    • Server侧,两条消息都作为pointer传递

class AddressBookService final : public expcmake::AddressBook::Service {
    public:
        virtual ::grpc::Status GetAddress(::grpc::ServerContext* context, const ::expcmake::NameQuerry* request, ::expcmake::Address* response)
{

// omitting unnecessary lines

// populate bar_array with std::complex<int> data
std::complex<int> z4 = 1. + 2i, z5 = 1. - 2i; // conjugates
bar_array = {z4, z5};

std::cout << "bar array printing whose size: " << bar_array.size() << std::endl;
for(int i = 0; i < bar_array.size(); i++) {
    std::cout << bar_array[i] << " ";
}
std::cout << std::endl;

// Use parent_data_list protocol buffer message type to fill with the content of bar_array
for (int i = 0; i < bar_array.size(); i++){
    
    // Use child_data protocol buffer message type to fill with the content of complex int data
    response->mutable_child_data_var()->add_child_data_list(real(bar_array[i]));
    response->mutable_child_data_var()->add_child_data_list(imag(bar_array[i]));
    
    // Use parent_data_list protocol buffer message type to fill with the content of child_data -> child_data_list data
    response->add_parent_data_list() -> child_data_list();
    
    // clear the child_data message. Reason to keep child_data_list new in every iteration otherwise add_child_data_list will append new data (eg: 1,2,1,-2) which is wrong. Expected is (1,2) then (1,-2)
    response->mutable_child_data_var()->clear_child_data_list();
}

// This is zero which I have got. Without clearing it is 4 which is also correct I believe as per the concept of protocol buffer message type
std::cout << "response->mutable_child_data_var()->child_data_list_size(): " << response->mutable_child_data_var()->child_data_list_size() << std::endl; 

// This is 2 which meets my requirement
std::cout << "response->parent_data_list_size(): " << response->parent_data_list_size() << std::endl;

// omitting unnecessary lines

}
};

  • client.cpp

int main(int argc, char* argv[])
{
    // Setup request
    expcmake::NameQuerry query;
    expcmake::Address result;
    // printing the content of child_data -> child_data_list data array/container. There I have seen 1,2,1,-2 if I don't do the clear operation on child_data_list in server side. So, I guess it is correctly got the data 
          for(int i = 0; i < result.mutable_child_data_var()->child_data_list_size(); i++)
            std::cout << "Child Data at index [" << i << "]: " << result.mutable_child_data_var()->child_data_list(i) << std::endl;

    // This one making problem
    // printing the content of parent_data_list type/container
    // for(int i = 0; i < result.parent_data_list_size(); i++){
    //   std::cout << "Parent Data at index [" << i << "]: " << result.mutable_parent_data_list(i) << std::endl; // This give me the memory address

    // Tried others to fetch the data but failed. Eg: result.parent_data_list(i) // failed
    // 
    // }
}
  • 来自生成的pb文件的代码段
  // repeated int32 child_data_list = 1;
  int child_data_list_size() const;
  private:
  int _internal_child_data_list_size() const;
  public:
  void clear_child_data_list();
  private:
  ::PROTOBUF_NAMESPACE_ID::int32 _internal_child_data_list(int index) const;
  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int32 >&
      _internal_child_data_list() const;
  void _internal_add_child_data_list(::PROTOBUF_NAMESPACE_ID::int32 value);
  ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int32 >*
      _internal_mutable_child_data_list();
  public:
  ::PROTOBUF_NAMESPACE_ID::int32 child_data_list(int index) const;
  void set_child_data_list(int index, ::PROTOBUF_NAMESPACE_ID::int32 value);
  void add_child_data_list(::PROTOBUF_NAMESPACE_ID::int32 value);
  const ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int32 >&
      child_data_list() const;
  ::PROTOBUF_NAMESPACE_ID::RepeatedField< ::PROTOBUF_NAMESPACE_ID::int32 >*
      mutable_child_data_list();


  // .expcmake.child_data child_data_var = 8;
  bool has_child_data_var() const;
  private:
  bool _internal_has_child_data_var() const;
  public:
  void clear_child_data_var();
  const ::expcmake::child_data& child_data_var() const;
  PROTOBUF_MUST_USE_RESULT ::expcmake::child_data* release_child_data_var();
  ::expcmake::child_data* mutable_child_data_var();
  void set_allocated_child_data_var(::expcmake::child_data* child_data_var);
  private:
  const ::expcmake::child_data& _internal_child_data_var() const;
  ::expcmake::child_data* _internal_mutable_child_data_var();
  public:
  void unsafe_arena_set_allocated_child_data_var(
      ::expcmake::child_data* child_data_var);
  ::expcmake::child_data* unsafe_arena_release_child_data_var();


  // repeated .expcmake.child_data parent_data_list = 9;
  int parent_data_list_size() const;
  private:
  int _internal_parent_data_list_size() const;
  public:
  void clear_parent_data_list();
  ::expcmake::child_data* mutable_parent_data_list(int index);
  ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::expcmake::child_data >*
      mutable_parent_data_list();
  private:
  const ::expcmake::child_data& _internal_parent_data_list(int index) const;
  ::expcmake::child_data* _internal_add_parent_data_list();
  public:
  const ::expcmake::child_data& parent_data_list(int index) const;
  ::expcmake::child_data* add_parent_data_list();
  const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::expcmake::child_data >&
      parent_data_list() const;

我想

  • 消息字段填写错误!!虽然大小并不是说
  • 我没有正确捕获protobuf syntax(在pb文件中生成)来获取数据

需要建议(如果也能提供语法会很有帮助)。

推荐答案

前缀API用于变异(修改/添加)元素,它们返回一个指针。mutable_*set_*接口只能在填写数据时使用。填充数据后,不应使用mutable_*API检查大小。在收到来自服务器的响应后,客户端很可能正在使用它,而不是变异。您需要相应地更新客户端。

还可以使用range-based for loop迭代child_data_varchild_data_list,如下所示:

const auto child_data_list = result.child_data_var().child_data_list();
for (const auto element : child_data_list)
{
    // process element
}

除此之外,您可以使用std::array(固定大小的数组),即std:array<std::complex<int>, 2>,或者使用另一种不表示固定大小的数组的repeated建模方法。

complex.proto

syntax = "proto3";

package pb;

message Complex {
    int32 real = 1;
    int32 imag = 2;
}

message Compound {
    Complex c1 = 1;
    Complex c2 = 2;
}

消息Complex仅用c1c2两个元素模拟std::complex类型和Compoundstd::array

有了它,您可以轻松地将Protobuf消息转换为std::complex,反之亦然。转换为std::complex后,您可以根据需要执行其支持的操作。

  • 编译complex.proto
protoc --cpp_out=. ./complex.proto

对于C++API,在public下生成的complex.pb.h文件中查找访问器。官方文档Protocol Buffer Basics: C++还在The Protocol Buffer API部分列出了C++API示例。

下面是一个完整的C++示例,上面的complex.proto

main.cpp

#include <iostream>
#include <complex>
#include <array>
#include <cstdlib>

#include "complex.pb.h"

namespace my {
    using complex = std::complex<int>;
    using compound = std::array<std::complex<int>, 2>;
}

int main()
{
    const auto my_c1 = my::complex{ 1, 2 };
    const auto my_c2 = my::complex{ 2, 4 };
    const auto my_compound_1 = my::compound{ my_c1, my_c2 };

    std::cout << "my_compound_1 [size: " << my_compound_1.size() << "]
";
    std::cout << "my_c1: " << my_c1 << '
';
    std::cout << "my_c2: " << my_c2 << '
';

    pb::Compound pb_compound;
    pb_compound.mutable_c1()->set_real(my_compound_1[0].real());
    pb_compound.mutable_c1()->set_imag(my_compound_1[0].imag());
    pb_compound.mutable_c2()->set_real(my_compound_1[1].real());
    pb_compound.mutable_c2()->set_imag(my_compound_1[1].imag());

    std::cout << "
pb_compound:
";
    pb_compound.PrintDebugString();

    const auto serialized_compound = pb_compound.SerializeAsString();

    // send

    // receive

    pb::Compound deserialized_compound;
    if (!deserialized_compound.ParseFromString(serialized_compound))
    {
        std::cerr << "[ERROR] Parsing failed!
";
        return EXIT_FAILURE;
    }
    
    std::cout << "

pb_compound (deserialized):
";
    deserialized_compound.PrintDebugString();

    const auto pb_c1 = deserialized_compound.c1();
    const auto pb_c2 = deserialized_compound.c2();

    const auto my_c3 = my::complex{ pb_c1.real(), pb_c1.imag() };
    const auto my_c4 = my::complex{ pb_c2.real(), pb_c2.imag() };
    const auto my_compound_2 = my::compound{ my_c3, my_c4 };

    std::cout << "my_compound_2 [size: " << my_compound_2.size() << "]
";
    std::cout << "my_c3: " << my_c3 << '
';
    std::cout << "my_c4: " << my_c4 << '
';

    const auto sum = my_c3 + my_c4;
    std::cout << "sum: " << sum << '
';

    return EXIT_SUCCESS;
}
  • 使用g++编译:
g++ main.cpp complex.pb.cc -o pb_complex `pkg-config --cflags --libs protobuf`
  • 运行:
$ ./pb_complex
my_compound_1 [size: 2]
my_c1: (1,2)
my_c2: (2,4)

pb_compound:
c1 {
  real: 1
  imag: 2
}
c2 {
  real: 2
  imag: 4
}


pb_compound (deserialized):
c1 {
  real: 1
  imag: 2
}
c2 {
  real: 2
  imag: 4
}
my_compound_2 [size: 2]
my_c3: (1,2)
my_c4: (2,4)
sum: (3,6)

这篇关于如何获取重复消息数据的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆