I do my first footsteps with boost asio and google proto. I defined a small test message
message Test
{
optional string test=1;
optional int32 value=2;
}
and one async boost asio server which response with the following function:
void start()
{
Test test;
test.set_test("test");
test.set_value(44444);
test.PrintDebugString();
boost::asio::async_write(socket_, boost::asio::buffer(test.SerializeAsString()),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
my test client is
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include "test.pb.h"
using boost::asio::ip::tcp;
int main(int argc, char* argv[])
{
try
{
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::endpoint end_point(boost::asio::ip::address::from_string("127.0.0.1"), 15000);
tcp::socket socket(io_service);
socket.connect(end_point);
std::string data;
for (;;)
{
boost::array<char, 128> buf;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
if (error == boost::asio::error::eof)
{
Test test;
test.ParseFromString(data);
test.PrintDebugString();
break; // Connection closed cleanly by peer.
}
else if (error)
throw boost::system::system_error(error); // Some other error.
data.append(buf.begin(), buf.end());
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
If i call my server with my client a few times i get different outputs:
test: "test"
value: 44444
533 {
}
test: "test"
value: 44444
1644{
}
test: "test"
value: 44444
the last output is as expected the rest is wrong. I dont understand why i get a bigger output then I have on my server :
test: "test"
value: 44444
Anyone has an idea why i get something like "1644{ }" ?
I think my eof is wrong or?
EDIT
message Header
{
required int32 size=1;
}
new start
void start()
{
boost::asio::async_read(socket_,
boost::asio::buffer(m_headerData, m_sizeOfHeader),
boost::bind(&tcp_connection::handle_read_header, this,
boost::asio::placeholders::error));
}
members:
const size_t m_sizeOfHeader = sizeof(Header::default_instance().SerializeAsString());
boost::array<char, sizeof(Header::default_instance().SerializeAsString())> m_headerData;
void handle_read_header(const boost::system::error_code& error_code)
{
if (!error_code)
{
Header header;
header.ParseFromString(std::string(m_headerData.begin(), m_headerData.end()));
header.PrintDebugString();
}
else
{
std::cout << error_code.message()<< "ERROR DELETE READ \n";
delete this;
}
I tried my header on this way now, but i get following errors:
Operation canceled or Bad file descriptor
My new client sends :
Header header;
header.set_size(101);
boost::asio::write(socket,boost::asio::buffer(header.SerializeAsString())) ;
I think the problem is that the variable m_sizeOfHeader is wrong... on my server side i get 8, and when i print the output of write on client I get 2...
I dont understand why my sizes for the header are not fixed... i just have one required field
You are ignoring number of bytes read (
len
) and append garbage todata
with:try instead:
Also your code will correctly work only if a single message is sent and socket immediately gracefully closed (with
shutdown
) after that. In more complex scenario you'll need some kind of protocol that allows to determine message bounds. For instance, you can send message size in first two bytes before message and on receiving side first read two bytes with expected message size, then read message body.