web-dev-qa-db-ja.com

Boostを使用してデータ構造をシリアル化して送信しますか?

私は次のようなデータ構造を持っています:

 typedef struct 
 {
 unsigned short m_short1; 
 unsigned short m_short2; 
 unsigned char m_character; 
} MyDataType; 

Boost :: serializationを使用してこのデータ構造をシリアル化し、boost :: asioを使用してTCP/IP経由で送信し、別のアプリケーションにデータを受信させ、同じBoostライブラリを使用して逆シリアル化します。

私はboost :: serializationチュートリアルをフォローしようとしています 、( 他のいくつかのSO質問が示唆しているように ))しかし、例は特にboost :: asioを使用したソケットではなく、ファイルへの書き込み/読み取り。

私はその仕事に適したツールを持っていると確信しています-私はそれらを一緒に機能させるための助けが必要です。ソケットへの書き込みは、ファイルへの書き込みとそれほど違いはありませんよね?

どんな提案でも大歓迎です。ありがとう!

22
Runcible

このような単純な構造の場合、boost :: serializationはやり過ぎで大きなオーバーヘッドになります。

もっと簡単に:

vector<uint16_t> net(3,0);

net[0]=htons(data.m_short1);
net[1]=htons(data.m_short2);
net[2]=htons(data.character);

asio::async_write(socket,buffer((char*)&net.front(),6),callback);

vector<uint16_t> net(3,0);
asio::async_read(socket,buffer((char*)&net.front(),6),callback);

callback:
data.m_short1=ntohs(net[0]);
data.m_short2=ntohs(net[1]);
data.character=ntohs(net[2]);

そして、boost :: serializationが持っている巨大なオーバーヘッドを節約してください

また、同じバイト数(大/小)のコンピューターが機能するプライベートプロトコルの場合、構造をそのまま送信します-POD。

6
Artyom

Asioのドキュメントには適切なシリアル化があります exampleserver.cppstock.hppconnection.hpp

スニペットは次のとおりです。

std::ostringstream archive_stream;
boost::archive::text_oarchive archive(archive_stream);
archive << your_struct;
outbound_data_ = archive_stream.str();
boost::asio::async_write(socket_, 
    boost::asio::buffer(outbound_data_), handler);
30
hvintus

Boostを使用してC++ structをシリアル化しようとしている人とこれを共有したいと思いました。上記の例では、structをシリアル化可能にするには、serialize関数を追加します。

typedef struct
{
  unsigned short m_short1;
  unsigned short m_short2;
  unsigned char m_character;

  template <typename Archive>
  void serialize(Archive& ar, const unsigned int version)
  {
    ar & m_short1;
    ar & m_short2;
    ar & m_character;
  }
} MyDataType;
22
Tymek

編集:私は以下の私の答えを取り戻します、私が提案したものは文字列ストリームソリューションよりも時間とスペースの利点がありますが、asio :: stream APIには長期的に必要となるいくつかの重要な機能が欠けています(例えば、時限中断)。


私の最初の答え:

Boost :: asioからのストリームを使用します。std:: stringstreamsに書き込んでから一度に送信するよりも時間とスペースの利点があります。方法は次のとおりです。

クライアントコード:

boost::asio::ip::tcp::iostream stream("localhost", "3000");

if (!stream)
  throw std::runtime_error("can't connect");

サーバーコード:

boost::asio::io_service ios;
boost::asio::ip::tcp::endpoint endpoint
  = boost::asio::ip::tcp::endpoint(ip::tcp::v4(), 3000);
boost::asio::ip::tcp::acceptor acceptor(ios, endpoint);
boost::asio::ip::tcp::iostream stream;

// Your program stops here until client connects.
acceptor.accept(*stream.rdbuf()); 

そして、クライアントストリームまたはサーバーストリームのいずれかに接続した後、次の手順を実行します。

MyDataType obj;

// Send the object.
boost::archive::text_oarchive archive(stream);
archive << obj;

// Or receive it.
boost::archive::text_iarchive archive(stream);
archive >> obj;

もちろん、Tymekが回答に書いたように、MyDataTypeに「serialize」関数を追加する必要があります。

4
Peter Jankuliak

ブーストシリアル化アーカイブは、任意のストリームで構築できます。したがって、任意のoarchiveは任意のostreamを使用でき、任意のiarchiveは任意のistreamを使用できます。したがって、ostringstreamにアーカイブし、asioを使用して文字列を送信し、そこからデータを再構築できます。

たとえば、binary_oarchive here のリファレンスを参照してください。

1
rlbond

コンストラクターパラメーターを取得するboost :: archiveにシリアル化を実行します-データを保存する宛先ストリーム。 boost.iostreamsライブラリを使用して、ネットワーク経由でデータを送信する独自​​のストリームを定義できます。代わりに、ファイルを使用するか、asioソケットストリームを使用します( http://www.boost.org/doc/libs/1_36_0/doc/ html/boost_asio/reference/ip__tcp/iostream.html )。これは良い方法です。これについても同様のことを行いましたが、ストリーム(Zip /暗号化/送信)がほとんどなく、すべての操作にブーストiostreamライブラリを使用しました。

簡単でダミーの方法-データを一時ファイルに保存し、このファイルを送信します:)

1
bayda

最初にメモリにアーカイブしてから、それをソケットに書き込むことをお勧めします。

0
Matt Cruikshank