2011-01-26 11 views
9

Sto provando a hackerare un client insieme in C++ usando Google Protocol Buffers e boost :: asio.Invio di messaggi Protobuf con boost :: asio

Il mio problema è che non so come posso inviare il messaggio protobuf ad asio. Quello che ho è questa:

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

Ora so che la segue è sbagliato, ma vi posterò in ogni modo:

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

ho ottenuto quanto che io so che devo comprimere il mio messaggio in modo diverso nel buffer, ma come?

In generale, sto attraversando un periodo difficile per capire come potenziare: asio funziona. Ci sono alcuni tutorial, ma di solito coprono solo l'invio di formati di dati standard come ints, che funziona immediatamente. Ho pensato che il mio problema è serializzazione, ma d'altra parte ho imparato che protobuf dovrebbe fare questo per me ... e ora sono confuso;)

Grazie per il vostro aiuto!

-> Daniel Gehriger ha fornito la soluzione, grazie mille!

risposta

8

io non so molto di buffer di protocollo di Google, ma provare quanto segue:

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

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

boost::asio::write(*sock, b); 
+5

Sarà necessario aggiungere ulteriori informazioni allo stream in modo da poter leggere correttamente l'oggetto PlayerInfo dall'altra parte. Protobuf non incorpora direttamente il tipo di oggetto nello stream. Non penso che contenga la lunghezza, ma dovrei controllare la documentazione. A proposito, ASIO non sa nulla sugli oggetti; si occupa solo di byte. Tienilo a mente quando leggi gli esempi e la documentazione. – Dan

+0

Daniel Gehriger: Grazie mille! Ha funzionato! – adi64

+0

Dan: Sì, ho pensato di dover aggiungere la dimensione in anticipo in modo che il server sia in grado di leggerlo ... Grazie! – adi64

2

Ho appena iniziato a utilizzare Google Protocol Buffers (protobuf) e aveva anche problemi nell'invio (e ricezione) i messaggi su una rete di computer.

In contrasto con l'API Java, l'API C++ non ha un metodo writeDelimitedTo per inviare un messaggio protobuf con un delimitatore. Senza un delimitatore, dobbiamo anche inviare la dimensione del messaggio, per poter decreterizzarlo sull'endpoint di ricezione.

L'API C++ offre la classe ::google::protobuf::io::CodedOutputStream, definita nel file di intestazione google/protobuf/io/coded_stream.h.

Il seguente codice sorgente dimostra come inviare un messaggio protobuf delimitato tramite Boost.Asio sul filo. L'esempio utilizza UDP. Dal momento che non ho trovato un esempio funzionante sul WWW, lo condivido qui.

#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; 
} 

Mentre scrivevo questo articolo, ho anche scoperto i seguenti due domande:

Entrambi sono legati a questa domanda e contengono anche (parziale) risposte. Spero che la mia risposta possa essere utile comunque.