Google :: protobuf + boost :: asio失败

我研究了现有的例子:

  1. 用boost :: asio发送Protobuf消息
  2. 使用boost :: asio :: read_async读取Protobuf对象
  3. Google Protocol Buffers:parseDelimitedFrom和writeDelimitedTo for C ++
  4. Java中协议缓冲区分隔的I / O函数有C ++等价物吗?
  5. 用boost :: asio发送Protobuf消息

但我仍然无法弄清楚如何使用Boost :: asio API传递Google Protobuf消息。 特别是对以下问题我没有清楚的认识:

  1. boost :: asio :: streambuf和google :: protobuf :: io对象之间的交互(以及应用最后一个的必要性)
  2. 正确实现消息stream(由于C ++ API中缺lesswriteDelimitedTo和parseDelimitedFrom方法)

这里是我的基于实例的 boost :: asio v。1.39 ssl_client的实现。

class client { public: client(boost::asio::io_service& io_service, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpoint_iterator) : socket_(io_service, context), request_stream(&b), raw_output(&request_stream), coded_output(&raw_output) { ... } void handle_connect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator endpoint_iterator) { ... } //Debugging function void print_buffers_condition(const char *step) { std::cout << "\nBuffer conditions after " << step << std::endl; std::cout << "boost::asio::streambuf\t\tb: " << b.size() << std::endl; std::cout << "google::protobuf::io::OstreamOutputStream raw_output: " << raw_output.ByteCount() << std::endl; std::cout << "google::protobuf::io::CodedOutputStream coded_output: " << coded_output.ByteCount() << std::endl; std::cout << std::endl; } //Sending test message after SSL Handshake void handle_handshake(const boost::system::error_code& error) { std::cout << "-----------------------------SENDING-----------------------------" << std::endl; print_buffers_condition("handle handshake"); if (!error) { SearchRequest msg; msg.set_query("qwerty"); msg.set_code(12345); std::cout << "Debugged" << std::endl; msg.PrintDebugString(); //Writing the length of the message before and serializing print_buffers_condition("before serialising"); coded_output.WriteVarint32(msg.ByteSize()); if (!msg.SerializeToCodedStream(&coded_output)) { std::cout << "serailizing error" << std::endl; } else { std::cout << "serializing success" << std::endl; } //Sending buffers_condition("before async write"); boost::asio::async_write(socket_, b, boost::bind(&client::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); buffers_condition("after async write"); } else { std::cout << "Handshake failed: " << error << "\n"; } } void handle_write(const boost::system::error_code& error, size_t bytes_transferred) { std::cout << " bytes_trransferred: " << bytes_transferred << std::endl; if (!error) { std::cout << "No error" << std::endl; ... } else { std::cout << "Write failed: " << error << "\n"; } } void handle_read(const boost::system::error_code& error, size_t bytes_transferred) { ... } private: boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; boost::asio::streambuf b; std::ostream request_stream; google::protobuf::io::OstreamOutputStream raw_output; google::protobuf::io::CodedOutputStream coded_output; }; 

这个代码是可操作的,所以在创build消息之后,我们将陷入void handle_write(const boost::system::error_code& error, size_t bytes_transferred)函数。 打印bytes_transferred_值返回0:服务器( 实例的基础上实例 )收到什么都没有。

debugging函数void print_buffers_condition(const char *step)的用法在通过一堆不同的缓冲对象进行传输时提示信息丢失:

  $ ./client 127.0.0.1 5000 -----------------------------SENDING----------------------------- Buffer conditions after handle handshake boost::asio::streambuf b: 0 google::protobuf::io::OstreamOutputStream raw_output: 8192 google::protobuf::io::CodedOutputStream coded_output: 0 Debugged: query: "qwerty" code: 12345 Buffer conditions after before serialization boost::asio::streambuf b: 0 google::protobuf::io::OstreamOutputStream raw_output: 8192 google::protobuf::io::CodedOutputStream coded_output: 0 serializing success Buffer conditions after before async write boost::asio::streambuf b: 0 google::protobuf::io::OstreamOutputStream raw_output: 8192 google::protobuf::io::CodedOutputStream coded_output: 13 Buffer conditions after after async write boost::asio::streambuf b: 0 google::protobuf::io::OstreamOutputStream raw_output: 8192 google::protobuf::io::CodedOutputStream coded_output: 13 bytes_trransferred: 0 

我不知道如何以适当的方式做到这一点。 OS是RHEL 6.4。 谢谢。

我对asio并不熟悉,但是在我看来,问题是你没有冲洗你的缓冲器。 数据卡在CodedOutputStream ,从来没有进入asio。

应该在堆栈上分配CodedOutputStream ,以便在完成消息写入后立即将其销毁。 析构函数将刷新缓冲区。 请注意, CodedOutputStream分配CodedOutputStream很便宜,因此将其放在堆栈上没有任何性能问题(事实上,这可能会更好)。

OstreamOutputStream可以类似地在堆栈上分配,但它堆 – 分配一个缓冲区,你可能想重用。 如果您选择重用相同的对象,请确保在CodedOutputStream被销毁后调用Flush()来刷新缓冲区。

顺便说一句, OstreamOutputStream不是特别有效,因为它必须在ostream已经做的顶部做自己的缓冲层。 您可能需要序列化为一个字符串( str = message.SerializeAsString()message.SerializeToString(&str) ),然后直接写入套接字(如果asio允许的话),因为这可能会避免冗余副本。