其他分享
首页 > 其他分享> > c-Google :: protobuf boost :: asio失败

c-Google :: protobuf boost :: asio失败

作者:互联网

我研究了现有的示例:

> Sending Protobuf Messages with boost::asio
> Reading Protobuf objects using boost::asio::read_async
> Google Protocol Buffers: parseDelimitedFrom and writeDelimitedTo for C++
> Are there C++ equivalents for the Protocol Buffers delimited I/O functions in Java?
> Sending Protobuf Messages with boost::asio

但我仍然不知道如何使用Boost :: asio API传递Google Protobuf消息.我尤其对以下问题没有清楚的了解:

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

这是我基于examples的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;
};

该代码是可操作的,因此在创建消息之后,我们陷入了空handle_write(const boost :: system :: error_code& error,size_t bytes_transferred)函数.打印bytes_transferred_值返回0:服务器(也基于examples实现)没有任何接收.

调试功能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

我不知道如何以适当的方式做到这一点.
操作系统是RHEL 6.4.
谢谢.

解决方法:

我对asio不熟悉,但是在我看来,问题在于您没有刷新缓冲区.数据卡在CodedOutputStream中,永远找不到进入asio的方式.

应该在堆栈上分配CodedOutputStream,以便在编写完消息后立即销毁它.析构函数将刷新缓冲区.请注意,CodedOutputStream的分配便宜,因此将其放在堆栈上没有性能问题(实际上,这样做可能更好).

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

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

标签:protocol-buffers,boost-asio,linux,c-4
来源: https://codeday.me/bug/20191122/2060502.html