1

I'm using cereal to serialize and deserialize data in c++, and I came upon a problem. I'm sending data using a socket to the client side, so i send a stringstream with the serialized files in a JSON format. The problem is that I can't deserialize it with simple data types, nor with complex ones, on the client side as it fails a rapidjson check and it tells me it's not an object

Here is the error

What would be the proper way of deserializing data considering that i can't create an instance of a class from the server side ?

Here is a simple example in which i try to send the username of a user to the client side

The send function :

void DBUser::SendUser()
{
    std::stringstream os;
    {
        cereal::JSONOutputArchive archive_out(os);
        archive_out(CEREAL_NVP(m_user));
    }
    ServerSocket* instance= ServerSocket::GetInstance();
    instance->SendData(os.str());
}

In case it is needed, here is the function used to send the stringstream to the client side

void ServerSocket::SendData(std::string message)
{
    try {
        asio::error_code ignored_error;
        asio::write(*socket, asio::buffer(message), ignored_error);
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

And here is the code when i try to deserialize:

std::array<char, 5000> buf;
asio::error_code error;
size_t len = socket.read_some(asio::buffer(buf), error);
std::string testString;
std::stringstream is(buf.data());
{
    cereal::JSONInputArchive archive_in(is);
    archive_in(testString);
}
std::cout << "Message from server: ";
std::cout << testString;
std::cout << std::endl;
Vasile Mihai
  • 103
  • 6
  • I'm not very familiar with `asio`, but looking at the shown code two questions come to mind: which part of `asio::write`'s documentation guarantees that the exact number of bytes that were requested to be written will actually be written, but rather than, like when writing to the socket directly, there is no such guarantee whatsoever; and what does the "some" part of `read_some` mean? Have you actually looked at what was read, in the end, from the socket, and confirm that the entire json object was actually read, before letting this json library chew on it? – Sam Varshavchik Dec 04 '21 at 15:34
  • oh, sorry, i didnt include that part of the code. the buffer has a test size for now of 5000, so it should be enough to guarantee that all the data is read. i have outputted the buffer for testing purposes before this and it was showing the full JSON so i don't think that the problem is with the data transfer. I'll add the declaration of the buffer to the code – Vasile Mihai Dec 04 '21 at 15:41
  • If you attempt to write ten megabytes to a TCP socket, then attempt to read ten megs from the other side of the socket into a ten megabyte buffer, you will discover that you did not write anywhere close to ten megabytes to a socket, nor read anywhere close to that much, from the other side of the socket. Sockets don't work like this. Any attempt to read or write from the socket must check for the actual number of bytes read or written, unless using a high-level library that will automatically handles retrying. This was my question to you: do you know if `asio` will actually do this for you? – Sam Varshavchik Dec 04 '21 at 15:46
  • i am not actually sure if asio does this for me as it is my first time using it and the documentation never mentioned anything of the sort – Vasile Mihai Dec 04 '21 at 15:51
  • Well, if the documentation is unclear, you can figure this out in about 10 seconds simply by printing exactly what was received from the socket, and solving this mystery. Or, even using your debugger to set a breakpoint, then inspect the contents of the read buffer in your debugger, to see if it's a complete json object. What did your debugger show you? – Sam Varshavchik Dec 04 '21 at 15:53
  • For the example i showed here: { "m_user": "testUser"; } – Vasile Mihai Dec 04 '21 at 15:59
  • That was it, wow, can you put this as an answer so i can mark the question as solved ? – Vasile Mihai Dec 04 '21 at 17:08

1 Answers1

1

You need to null terminate the received socket data. Can you try null terminating it like buf[len] = '\0'; after this size_t len = socket.read_some(asio::buffer(buf), error); statement.

Harry
  • 2,177
  • 1
  • 19
  • 33