Sending and receiving protobuf data over Socket via boost asio

大憨熊 提交于 2021-01-29 22:16:10

问题


I want to send Protobuf data from my server to my client thanks to a TCP socket.

I tested my client and my server and the TCP connexion works.

So I try to serialize my data and send it by using a streambuf.

In my server :

void SendData(protobufType data){
        std::ostream ostream(&this->m_streambuf);
        data.SerializeToOstream(&ostream);

        std::cout<<"Send data"<< std::endl;
        boost::asio::write(this->m_socket, this->m_streambuf);
}

In my client :

boost::asio::streambuf response;
boost::asio::read(socket, response);
std::cout<<"Data received"<< std::endl;

I run 3 times my send function (I guess my data seams to be sent) but myclient seams to never get data ...


回答1:


Your client hangs on this line

boost::asio::read(socket, response);

because above is the same as

boost::asio::read(socket, response, boost::asio::tranfer_all());

what is described in the documentation.

You use read overload which takes completion condition. There are three kinds of these functors: transfer_all_t, transfer_exactly_t and transfer_at_least_t. Each of them has operator()() which returns 0 if read operation is completion - see reference.

The code for transfer_all_t::opeator()() is:

  template <typename Error>
  std::size_t operator()(const Error& err, std::size_t)
  {
    return !!err ? 0 : default_max_transfer_size;
  }

so 0 is returned only if an error occurres.

transfer_at_least_t::operator()() is:

  template <typename Error>
  std::size_t operator()(const Error& err, std::size_t bytes_transferred)
  {
    return (!!err || bytes_transferred >= minimum_)
      ? 0 : default_max_transfer_size;
  }

as you can see 0 is returned if either an error occurred or at least minimum_ bytes were transferred.

If you know that read with transfer_all ends when an error occurres, you can create this error to see read data. You can shutdown socket (for sending operation) on the server side or just close this socket. Then you can change read call to get error_code and you should see End of file as error:

boost::system::error_code ec;
boost::asio::read(socket,response,ec);
if (ec)
{
   cout << ec.message() << endl; // End of file
   // if ec is End of file you can see what data was read into streambuf
}

You send a serialized object, so you know the size of this object, why not use the approach where you are sending the size of object (for example on 4 bytes) then after this header the content of object is sent later.

At the client side:

array<char,4> length;
boost::asio::read(socket,boost::asio::buffer(length));
int contentLen = /*conversion from length array into integer */
vector<char> content( contentLen );
boost::asio::read(socket,boost::asio::buffer(content));


来源:https://stackoverflow.com/questions/56327248/sending-and-receiving-protobuf-data-over-socket-via-boost-asio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!