Domanda

Ho una struttura di dati che assomiglia a questa:

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

Voglio usare boost :: serialization per serializzare questa struttura di dati, quindi usare boost :: asio per trasmetterli via TCP / IP, quindi fare in modo che un'altra applicazione riceva i dati e li serializzi usando le stesse librerie boost.

Sto cercando di seguire boost :: serializzazione tutorial , ( come alcune altre domande SO hanno suggerito ) ma l'esempio è specifico per scrivere / leggere su un file, non su un socket usando boost :: asio.

Sono abbastanza sicuro di avere gli strumenti giusti per il lavoro: ho solo bisogno di aiuto per farli lavorare insieme. Scrivere su un socket non può essere così diverso da scrivere su un file, giusto?

Eventuali suggerimenti sono molto apprezzati. Grazie!

È stato utile?

Soluzione

Per una struttura così semplice, boost :: serialization è eccessivo e sovraccarico enorme.

Semplifica:

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]);

E risparmia un ENORME sovraccarico che aumenta :: la serializzazione ha

E se hai un protocollo privato in cui funzionano i computer con lo stesso ordine di byte (grande / piccolo) che invia semplicemente la struttura così com'è - POD.

Altri suggerimenti

Esiste una buona serializzazione esempio nella documentazione di asio: server.cpp , stock.hpp , connection.hpp .

Ecco uno snippet:

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);

Ho pensato di condividerlo con chiunque cercasse di serializzare un struct in C ++ usando Boost. Per l'esempio sopra riportato, per rendere serializzabile struct devi aggiungere una funzione 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;

EDIT: riprendo la mia risposta di seguito, ciò che ho proposto ha i vantaggi di spazio e tempo rispetto alla soluzione stringstream ma l'API asio :: stream manca di alcune funzionalità importanti che saranno necessarie a lungo termine (ad es. interruzione temporizzata ).


La mia risposta originale:

Usa i flussi da boost :: asio, ha vantaggi di tempo e spazio rispetto a scriverlo in std :: stringstreams e poi inviarlo in una volta sola. Ecco come:

Codice client:

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

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

Codice server:

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()); 

E poi, dopo esserti connesso con il flusso client o server, fai semplicemente:

MyDataType obj;

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

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

Ovviamente devi aggiungere la funzione 'serializza' nel tuo MyDataType come Tymek ha scritto nella sua risposta.

Stai eseguendo la serializzazione per boost :: archive che ottiene il parametro del costruttore - flusso di destinazione, dove salverai i dati. È possibile utilizzare la libreria boost.iostreams per definire il proprio flusso che invierà i dati sulla rete, invece di archiviare o semplicemente utilizzare flussi socket asio ( http://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/reference/ip__tcp/iostream.html ). È un buon modo, abbiamo fatto qualcosa di simile su questo, ma abbiamo pochi stream (zip / encrypt / send) e abbiamo usato la libreria boost iostreams per tutte le operazioni.

Modo semplice e fittizio: archivia i tuoi dati in un file temporaneo e invia questo file :)

Gli archivi di serializzazione boost possono essere costruiti con qualsiasi flusso. Quindi qualsiasi oarchive può usare qualsiasi ostream e qualsiasi iarchive può usare qualsiasi istream. Quindi puoi archiviare su ostringstream, trasmettere la stringa con asio e ricostruire i dati da quello.

Vedi il riferimento di binary_oarchive qui , per esempio.

Sospetto che prima vorrai archiviare in memoria, quindi scriverlo nel socket.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top