gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 21:22:50 26 4
gpt4 key购买 nike

我研究了现有的例子:

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

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

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

这是我基于 boost::asio v. 1.39 ssl_client 的实现,来自 examples .

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

此代码是可操作的,因此在创建消息后我们进入 void 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 允许this),因为它可能会避免冗余拷贝。

关于c++ - Google::protobuf + boost::asio 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19839849/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com