Cap'n Proto C ++ сериализуется в массив char (или любой байтовый массив) - PullRequest
0 голосов
/ 01 апреля 2020

Моя цель - отправить сериализованные данные через MPI. Я сделал это с ProtoBuf, но я хотел бы попытаться использовать более быстрый метод сериализации, такой как Cap'n Proto (я попробую и другие, но здесь я застрял). В ProtoBuf я использую функцию SerializeToArray(void * data, int size), которая прекрасно работает.

Теперь я хочу сделать то же самое, но с Cap'n Proto, но нигде не могу найти, как это сделать (если у вас есть ссылку вышлите пожалуйста). Так как Cap'n Proto утверждает, что является более быстрой заменой ProtoBuf, я нахожу это удивительным. Может быть, я иду по этому совершенно неправильному пути.

Итак, мой вопрос звучит так:

Как мне сериализовать в массив char (или любой байтовый массив) с Cap'n Proto (если он это вообще возможно)? Или как мне сериализовать таким образом, чтобы его можно было легко передать через MPI с использованием C ++?

Ответы [ 2 ]

1 голос
/ 02 апреля 2020

Я не уверен, что это самый эффективный способ сделать это, но он работает.

файл messages.capnp:

@0xf46c6bd8234dfab9;

struct Testmessage {
  string @0 :Text;
  float @1 :Float32;
  int @2 :Int32;
}

run_cap_n_proto. cpp файл:

#include <iostream>
#include <capnp/serialize.h>
#include "messages.capnp.h"

int main()
{
    // Encode message
    ::capnp::MallocMessageBuilder message_builder;
    Testmessage::Builder message = message_builder.initRoot<Testmessage>();

    message.setString( "string" );
    message.setFloat( 3.14 );
    message.setInt( 1337 );

    auto encoded_array = capnp::messageToFlatArray(message_builder);
    auto encoded_array_ptr = encoded_array.asChars();
    auto encoded_char_array = encoded_array_ptr.begin();
    auto size = encoded_array_ptr.size();

    // Send message
    // Receive message

    // Decode message
    auto received_array = kj::ArrayPtr<capnp::word>(reinterpret_cast<capnp::word*>(encoded_char_array), size/sizeof(capnp::word));
    ::capnp::FlatArrayMessageReader message_receiver_builder(received_array);
    auto message_receiver = message_receiver_builder.getRoot<Testmessage>();
    auto s_r = message_receiver.getString().cStr();
    auto f_r = message_receiver.getFloat();
    auto i_r = message_receiver.getInt();

    std::cout << "received: " << s_r << ", " << f_r << ", " << i_r << std::endl;
}

Для компиляции messages.capnp:

$ capnp compile -oc++ messages.capnp

Для компиляции основной программы:

$ g++ -o run_cap_n_proto run_cap_n_proto.cpp messages.capnp.c++ `pkg-config --cflags --libs capnp`
0 голосов
/ 02 апреля 2020

Для сообщения, данного в этом примере AddrssBook из документации, вы можете сделать что-то вроде этого:

// Documentation: https://capnproto.org/cxx.html
// AddressBook example

void sendMessage( const char* data, const std::size_t size ); 

void writeAddressBook()
{
    ::capnp::MallocMessageBuilder message;

    auto addressBook = message.initRoot<AddressBook>();
    auto people = addressBook.initPeople(1);

    auto alice = people[0];
    alice.setId(123);
    alice.setName("Alice");
    alice.setEmail("alice@example.com");

    auto alicePhones = alice.initPhones(1);
    alicePhones[0].setNumber("555-1212");
    alicePhones[0].setType(Person::PhoneNumber::Type::MOBILE);
    alice.getEmployment().setSchool("MIT");

    // get char array and send

    const auto m = capnp::messageToFlatArray( message );
    const auto c = m.asChars();
    std::cout << c.size() << '\n';

    sendMessage( c.begin(), c.size() ); // pass as char array
}
...