Отправка сообщений Protobuf с boost :: asio - PullRequest
11 голосов
/ 27 января 2011

Я пытаюсь взломать клиента вместе в C ++, используя протоколы Google Buffers и boost :: asio.

Моя проблема в том, что я не знаю, как я могу передать сообщение protobuf в asio.Вот что у меня есть:

// set up *sock - works
PlayerInfo info;
info.set_name(name);
// other stuff

Теперь я знаю, что следующее неверно, но я все равно опубликую это:

size_t request_length = info.ByteSize();
boost::asio::write(*sock, boost::asio::buffer(info, request_length));

Я дошел до того, что знаю, чтоЯ должен по-разному упаковать свое сообщение в буфер - но как?

Вообще, мне трудно понять, как работает boost :: asio.Существуют некоторые учебные пособия, но они обычно охватывают отправку стандартных форматов данных, таких как целые, которые работают "из коробки".Я подумал, что моя проблема в сериализации , но с другой стороны я узнал, что protobuf должен сделать это для меня ... и теперь я в замешательстве;)

Спасибо за вашу помощь!

-> Даниэль Геригер предоставил решение, большое спасибо!

Ответы [ 2 ]

10 голосов
/ 27 января 2011

Я не знаю много о буфере протокола Google, но попробуйте следующее:

PlayerInfo info;
info.set_name(name);
// ...

boost::asio::streambuf b;
std::ostream os(&b);
info.SerializeToOstream(&os);

boost::asio::write(*sock, b);
2 голосов
/ 05 декабря 2013

Я только начал использовать Буферы протокола Google (protobuf) , а также имел проблемы с отправкой (и получением) сообщений по компьютерной сети.

В отличие от API Java,API C ++ не имеет метода writeDelimitedTo для отправки сообщения protobuf с разделителем.Без разделителя мы также должны отправить размер сообщения, чтобы иметь возможность десериализации его в конечной точке приема.

API C ++ предлагает класс ::google::protobuf::io::CodedOutputStream, определенныйв заголовочном файле google/protobuf/io/coded_stream.h.

Следующий исходный код демонстрирует, как с помощью Boost.Asio через провод отправлять разделенное сообщение protobuf с разделителями.В примере используется UDP.Поскольку я не нашел рабочего примера в WWW, я делюсь им здесь.

#include "boost/asio.hpp"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"

using ::boost::asio::ip::udp;

int main() {
  PlayerInfo message;
  message.set_name("Player 1");
  // ...

  const boost::asio::ip::address_v4 kIpAddress = boost::asio::ip::address_v4::loopback();
  const unsigned short kPortNumber = 65535;

  try {
    boost::asio::io_service io_service;
    udp::socket socket(io_service, boost::asio::ip::udp::v4());

    udp::endpoint endpoint(kIpAddress, kPortNumber);
    boost::system::error_code error;

    boost::asio::streambuf stream_buffer;
    std::ostream output_stream(&stream_buffer);

    {
      ::google::protobuf::io::OstreamOutputStream raw_output_stream(&output_stream);
      ::google::protobuf::io::CodedOutputStream coded_output_stream(&raw_output_stream);
      coded_output_stream.WriteVarint32(message.ByteSize());

      message.SerializeToCodedStream(&coded_output_stream);
      // IMPORTANT: In order to flush a CodedOutputStream it has to be deleted,
      // otherwise a 0 bytes package is send over the wire.
    }
  }

  size_t len = socket.send_to(stream_buffer.data(), endpoint, 0, error);

  if (error && error != boost::asio::error::message_size) {
    throw boost::system::system_error(error);
  }

  std::cout << "Sent " << len << " bytes data to " << kIpAddress.to_string() << "." << std::endl;
} catch (const std::exception& ex) {
  std::cerr << ex.what() << std::endl;
}

Во время написания этой статьи я также обнаружил следующие два вопроса:

Оба относятся кэтот вопрос, а также содержат (частичные) ответы.Я надеюсь, что мой ответ может быть полезен в любом случае.

...