How to transfer serialized data to the server and deserelize it - c++

I use the enet library to write the client and server side of the code, and also decided to use the boost library to serialize the data. I used something like this code to send data and serialize it
char message_data[80] = "somedata";
std::stringstream ss;
boost::archive::binary_oarchive oa{ ss };
oa << message_data;
SendPacket(peer, ss.str());
and something like this code for getting data and deserializing it
std::string deser_data;
std::string some_data = (char*)event.packet->data;
std::stringstream ss(some_data);
boost::archive::binary_iarchive ia{ ss };
ia >> deser_data;
But this code does not work, I think it is due to incorrect use of stringstream, but this is not accurate

Is there some reason you want to use a binary (non-portable, change-intolerant) representation? JSON has become a bit of a standard. Be that as it may...
I would add some debug. What length are you writing? What length are you reading? If you dump the buffers, are they identical on client and server?
Does the code work if you do it all inline (no network involved)? That is, can you write a unit test to do both the client and server side where you construct an object, serialize it, deserialize into another object, and then compare them?
I'd start with that.
Sorry, this isn't a proper answer, but it's too long for a simple comment.

Related

Issue with boost serialization not dearchiving when data length is over a specific value

Okay, so I am trying to send a struct with boost asio. The send on the client-side works fine and the read_until also seems fine. However, when it tries to deserialize the data back to the struct it won't work when the size of the archive is greater than about 475 in length. The rest of the struct gets ignored for some reason and only the data field gets printed. I also added screenshots of the output. Basically, when the whole struct is not received there is an input stream error on the line ba >> frame. I also tested both with a larger file and get the same error. I even tried serializing a vector as well so not sure where my error is.
EDIT:
I figured out the issue. When I was reading from the socket I had something like this...
boost::asio::read_until(socket, buf, "\0");
This was causing weird issues reading in all the data from the boost binary archive. To fix this issue I made a custom delimiter that I appended to the archive I was sending over the socket like...
boost::asio::read_until(socket, buf, "StopReadingHere");
This fixed the weird issue of the entire boost archive string not being read into the streambuf.
First Issue
ostringstream oss;
boost::archive::text_oarchive ba(oss);
ba << frame;
string archived_data = oss.str();
Here you take the string without ensuring that the archive is complete. Fix:
ostringstream oss;
{
boost::archive::text_oarchive ba(oss);
ba << frame;
}
string archived_data = oss.str();
Second issue:
boost::asio::read_until(socket, buf, "\0");
string s((istreambuf_iterator<char>(&buf)), istreambuf_iterator<char>());
Here you potentially read too much into s - buf may contain additional data after the '\0'. Use the return value from read_until and e.g. std::copy_n, following buf.consume(n).
If you then keep the buf instance for subsequent reads you will still have the previously read remaining data in the the buffer. If you discard it, that will lead to problems deserializing the next message.
Risky Code?
void write(tcp::socket& socket, string data, int timeout) {
auto time = std::chrono::seconds(timeout);
async_write(socket, boost::asio::buffer(data), transfer_all(), [&] (error_code error, size_t bytes_transferred) {
});
service.await_operation(time, socket);
}
You're using async operation, but passing local variables (data) as buffer.The risk is that data becomes invalid as soon as write returns.
Are you making sure that async_write is always completed before exiting from write? (It is possible that await_operation achieves this for you.
Perhaps you are even using await_operation from my own old answer here How to simulate boost::asio::write with a timeout . It's possible since things were added that some assumptions no longer hold. I can always review some larger piece of code to check.

multi sockets in boost asio?

I wanted to make a chat server using boost::asio and as the program gets more complicated and difficult for myself to read, I was wondering if it is possible to use several sockets in the same client and on server side?
If I can't make myself quite clear to you, for example, in my server side I have int and string variables and I want to send them in different sockets NOT effecting to each other.
Well... int variable is sent through socket1 and string is through socket2. The same thing with a client side that it should "know" from which socket int is "coming" and from which string. If this is possible I would be very glad to see some examples :)
Thank you in advance!
the program gets more complicated and difficult for myself to read
You might want to refactor a bit. Even large code should be easy to read and understand.
I have int and string variables and I want to send them in different sockets NOT effecting to each other.
You don't create a new socket for each data-type you want to send. Add a proper header to your message and parse the received data-type with error checking.
For instance (simplified case):
std::string tx = "12345678Test";
std::stringstream ss(tx);
int num;
ss >> num;
std::string s;
ss >> s;

Reading binary data in memory into a stringstream and stream this over a socket

I would like to know if it is possible to, for instance, take a piece of data in memory, read it into an output stringstream (as binary data) and write this onto a socket for a client application to process.
The problem I run into while attempting this is the following:
Example:
char name[1024] = "Test";
std::ostringstream message (std::stringstream::out | std::stringstream::binary);
len = strlen(name);
message.write(reinterpret_cast<const char*>(&len), sizeof(int));
message.write(test, len*sizeof(char));
I want to write this stringstream to the socket with all of the data in it, but the problem is this: The stringstream write only executes the first time, in this case writing 4 (the length of the string) and none of the subsequent writes. Am I missing something here?
If this is not the best way to do it, what would be the best way to accomplish this? This is partly to reduce file I/O for cached memory snapshots.
Thanks in advance..
Your code (with minor fixes) appears to work for me, so you might check to be sure that you are correctly handling the buffered binary data, i.e. you do not assume that the std::string contains a string.

Serializing an object with Boost for Named Pipes in c++

I am attempting to serialize some EEG data from a command line application using the Boost library for the serialization and sending that serialized data over a named pipe to a user interface Form built in Visual Studio C++ 2010.
From the boost library tutorial I am able to serialize my data structure, and, http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/tutorial.html#simplecase
from this tutorial on Win32 named pipes, I can construct pipes and send text between applications.
http://avid-insight.co.uk/joomla/component/k2/item/589-introduction-to-win32-named-pipes-cpp?tmpl=component&print=1
The boost library tutorial serializes for a text file:
std::ofstream ofs("filename");
// create class instance
const gps_position g(35, 59, 24.567f);
// save data to archive
{
boost::archive::text_oarchive oa(ofs);
// write class instance to archive
oa << g;
// archive and stream closed when destructors are called
}
I want to know what do I need to serialize to in order to send my data structure over a named pipe? The IOstream c++ library seems to always need a file to stream to/from?http://www.cplusplus.com/reference/iostream/
I don't want o serialize to a file and I am not sure what to serialize to? I would really appreciate it if you could tell me what I need to serialize to and it would be great if you could tell me whether another boost command will be required other than boost::archive::text_oarchive , as I have been unable to find an alternative.
Thank you for your time! It is really appreciated!
(This question has been asked before: Serialize and send a data structure using Boost? , but the person was told not to use boost as for his simple data structure boost would have too much overhead, so it really is still floating.)
Thanks ForEveR, very simple, don't know how I missed it! :) The solution in context with the two tutorials posted above:
const EEG_Info g(35, 59, 24.567f);
std::stringstream MyStringStream ;
boost::archive::text_oarchive oa(MyStringStream);
// write class instance to archive
oa << g;
// This call blocks until a client process reads all the data
string strData;
strData = MyStringStream.str();
DWORD numBytesWritten = 0;
result = WriteFile(
pipe, // handle to our outbound pipe
strData.c_str(), // data to send
strData.length(), // length of data to send (bytes)
&numBytesWritten, // will store actual amount of data sent
NULL // not using overlapped IO
);

sending a serialized type over a boost-asio socket connection using boost serialization

I am trying to send 1kb of data from a "server" to a "client", but I just can't get it right.
There are a few things that I NEED to do in this:
1) Need to use boost-asio sockets to transfer the data
2) Need to serialize a type I created (Packet) that will contain the data as a string or char*
Here is what is going on:
First, I get 1kb of data from a sample text file on the server. I get this and put it into the Packet type that I created. I have defined the data field in Packet to hold this data as a std::string. (I tried char* but it didnt work well - see next paragraph).
Second I serialize it using boost text_oarchive . I have no problems serializing the Packet type if it just contains a string, but what I really want is a way to serialize it with the data type being a char array (so that it works better with the socket below)
Third, I send it over a boost asio socket. Here I have a problem because I can't find a way to send a std::string over the socket connection. Everything I see as examples and in the documentation need a buffer using some type of char* and not a string.
its just a headache. can you help?
Everything I see as examples and in the documentation need a buffer
using some type of char* and not a string
That is correct, though it's quite simple to do using Boost.Serialization and Boost.Asio. You can serialize using a text_oarchive to a boost::asio::streambuf then send the resulting stream buffer contents using a socket.
See this question and my answer to that question for a more complete example.