2011-01-26 11 views
9

私は、C++でクライアントを一緒にハックしようとしていますが、Googleのプロトコルバッファとboost :: asioを使用しています。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がどのように動作するかを理解するのに苦労しています。いくつかのチュートリアルがありますが、通常はintsのような標準のデータ形式を送信するだけで、すぐに使用できます。私は私の問題はシリアライズであることを考え出したが、一方で私はいるProtobufが私のためにこれを行う必要があります...そして今私は混乱していることを知りました;)あなたの助けを

ありがとう!

- > Daniel Gehrigerがソリューションを提供しました。ありがとうございました!

答えて

8

私はGoogleのプロトコルバッファについて多くを知っているが、次のことをしようとしないでください:

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

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

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

もう一方の端のPlayerInfoオブジェクトを確実に読み取れるように、ストリームにさらに情報を追加する必要があります。 Protobufはオブジェクト型をストリームに直接埋め込むことはありません。私はそれも長さが含まれているとは思わないが、私はドキュメントを確認する必要があります。ところで、ASIOはオブジェクトについて知りません。それはバイトを扱うだけです。例とドキュメントを読むときは、それを覚えておいてください。 – Dan

+0

Daniel Gehriger:ありがとうございました!それはうまくいった! – adi64

+0

Dan:うん、私は、サーバーがそれを読むことができるようにサイズをあらかじめ追加しなければならないと思った...ありがとう! – adi64

2

私はちょうどGoogle Protocol Buffers (protobuf)を使用して開始しても問題の送信(および受信)コンピュータネットワークを介してメッセージを持っていました。

Java APIとは対照的に、C++ APIには、デリミタ付きのprotobufメッセージを送信するためのwriteDelimitedToメソッドがありません。 デリミタがなければ、受信エンドポイントでデシリアライズできるように、メッセージのサイズも送信する必要があります。

C++ APIは、google/protobuf/io/coded_stream.hというヘッダーファイルで定義されたクラス::google::protobuf::io::CodedOutputStreamを提供します。

以下のソースコードは、デリミタ付きprotobufメッセージをBoost.Asio経由で電信で送信する方法を示しています。この例では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; 
} 

は、私はまた、次の二つの質問を発見しました)答え。とにかく私の答えが役に立つと思う。

関連する問題