Сериализация двоичных данных в boost завершается с ошибкой «недопустимая подпись»

У меня возникают трудности с определением правильного способа использования ускоренной сериализации/asio для отправки объектов по сети. Класс message максимально прост. Это не подходит для С++ и не подходит для моих нужд, я просто временно упрощаю тестирование asio/ser:

class message {
    friend class boost::serialization::access;
public:
    message(){}
    int type;
    int sender;
    int assignment;
    int nogood;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & type;
        ar & sender;
        ar & assignment;
        ar & nogood;
    }
};

На стороне клиента, когда агент решает отправить сообщение, отправляет его на сервер через TCP-соединение:

message m;
// do something to generate message
boost::asio::streambuf bufx;
std::ostream os( &bufx );
boost::archive::binary_oarchive ar( os );
ar & m;
boost::asio::write( socket, bufx);

Код на стороне сервера:

boost::asio::streambuf bufx;
std::istream is(&bufx);
boost::archive::binary_iarchive ia(is);  // <--- Exception: invalid signature
size_t rcx = asio::read(socket,bufx);
message m;
ia >> m;

person sorush-r    schedule 18.05.2013    source источник


Ответы (2)


В вашем коде на стороне сервера ваш streambuf пуст, когда вы создаете двоичный архив. Если конструктор архива ищет магическое число в начале архива, то он его не найдет. Попробуйте заполнить streambuf вызовом boost::asio::read() перед созданием потока и архива.

person rhashimoto    schedule 18.05.2013
comment
Танки за ваш ответ. Я переместил read() сразу после определения streambuf. Теперь чтение вызывает исключение с этим сообщением: End of file - person sorush-r; 18.05.2013
comment
Я считаю, что это ожидаемо. read() блокируется до тех пор, пока буфер не заполнится или не произойдет ошибка. В этом случае ошибка заключается в том, что сокет закрылся. Вы можете использовать read() перегрузку, который возвращает статус через ссылочный аргумент boost::system::error_code, а не выдает ошибку. - person rhashimoto; 18.05.2013

У меня такое же исключение.

И это официальное пример помогает мне.

Если вы все еще в беде, попробуйте это.

size_t n = sock.receive(bufs);

// received data is "committed" from output sequence to input sequence
b.commit(n);

std::istream is(&b);
std::string s;
is >> s;

В моем случае я использую async_read. На самом деле, я изменил пример< /а>.

  boost::asio::streambuf inbound_;
  boost::asio::streambuf::mutable_buffers_type bufs = inbound_.prepare(inbound_data_size);
  void (connection::*f)(
      const boost::system::error_code&, std::size_t,
      T&, boost::tuple<Handler>)
    = &connection::handle_read_data<T, Handler>;
  boost::asio::async_read(socket_, boost::asio::buffer(bufs), 
    boost::bind(f, this,
      boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, boost::ref(t), handler));

А потом у обработчика

  /// Handle a completed read of message data.
  template <typename T, typename Handler>
  void handle_read_data(const boost::system::error_code& e, std::size_t bytes_transferred,
      T& t, boost::tuple<Handler> handler)
  {
    if (e)
    {
      boost::get<0>(handler)(e);
    }
    else
    {
      // Extract the data structure from the data just received.
      try
      {
        inbound_.commit(bytes_transferred);
        std::istream archive_stream(&inbound_);
        boost::archive::binary_iarchive archive(archive_stream);
        archive >> t;
      }
      catch (std::exception& err)
      {
        // Unable to decode data.
        boost::system::error_code error(boost::asio::error::invalid_argument);
        boost::get<0>(handler)(error);
        return;
      }

      // Inform caller that data has been received ok.
      boost::get<0>(handler)(e);
    }
  }
person heon    schedule 11.04.2014