问题
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