Lucas Arbiza
Lucas Arbiza

Reputation: 273

How to serialize an object to send over network

I'm trying to serialize objects to send over network through a socket using only STL. I'm not finding a way to keep objects' structure to be deserialized in the other host. I tried converting to string, to char* and I've spent a long time searching for tutorials on the internet and until now I have found nothing.

Is there a way to do it only with STL?

Are there any good tutorials?

I am almost trying boost, but if there is how to do it with STL I'd like to learn.

Upvotes: 8

Views: 17758

Answers (5)

Duncan Iglesias
Duncan Iglesias

Reputation: 43

Serializing C++ Objects over a Network Socket

This is 6 years late but I just recently had this problem and this was one of the threads that I came across in my search on how to serialize object through a network socket in C++. This solution uses just 2 or 3 lines of code. There are a lot of answers that I found work but the easiest that I found was to use reinterpret_cast<obj*>(target) to convert the class or structure into an array of characters and feed it through the socket. Here's an example.

Class to be serialized:

/* myclass.h */

#ifndef MYCLASS_H
#define MYCLASS_H

class MyClass
{
    public:
        int A;
        int B;
        MyClass(){A=1;B=2;}
        ~MyClass(){}
};

#endif

Server Program:

/* server.cpp */

#include "myclass.h"

int main (int argc, char** argv)
{
    // Open socket connection.
    // ...

    // Loop continuously until terminated.
    while(1)
    {
        // Read serialized data from socket.
        char buf[sizeof(MyClass)];
        read(newsockfd,buf, sizeof(MyClass));
        MyClass *msg = reinterpret_cast<MyClass*>(buf);  

        std::cout << "A = " << std::to_string(msg->A) << std::endl;
        std::cout << "B = " << std::to_string(msg->B) << std::endl;
    }

    // Close socket connection.
    // ...

    return 0;
}

Client Program:

/* client.cpp */

#include "myClass.h"

int main(int argc, char *argv[])
{
    // Open socket connection.
    // ...

    while(1)
    {
        printf("Please enter the message: ");
        bzero(buffer,256);
        fgets(buffer,255,stdin);

        MyClass msg;
        msg.A = 1;
        msg.B = 2;

        // Write serialized data to socket.
        char* tmp = reinterpret_cast<char*>(&msg);
        write(sockfd,tmp, sizeof(MyClass));
    }

    // Close socket connection.
    // ...

    return 0;
}

Compile both server.cpp and client.cpp using g++ with -std=c++11 as an option. You can then open two terminals and run both programs, however, start the server program before the client so that it has something to connect to.

Hope this helps.

Upvotes: 1

MYLOGOS
MYLOGOS

Reputation: 681

I think you should use google Protocol Buffers in your project.In network transport Protocol buffers have many advantages over XML for serializing structured data. Protocol buffers:

are simpler are 3 to 10 times smaller are 20 to 100 times faster are less ambiguous generate data access classes that are easier to use programmaticall

and so on. I think you need read https://developers.google.com/protocol-buffers/docs/overview about protobuf

Upvotes: 0

Lucas Arbiza
Lucas Arbiza

Reputation: 273

I got it!

I used strinstream to serialize objects and I sent it as a message using the stringstream's method str() and so string's c_str().

Look.

class Object {
public:
int a;
string b;

void methodSample1 ();
void methosSample2 ();

friend ostream& operator<< (ostream& out, Object& object) {
out << object.a << " " << object.b;   //The space (" ") is necessari for separete elements
return out;
}

friend istream& operator>> (istream& in, Object& object) {
in >> object.a;
in >> object.b;
return in;
}
};

/* Server side */
int main () {
Object o;
stringstream ss;
o.a = 1;
o.b = 2;
ss << o;    //serialize

write (socket, ss.str().c_str(), 20); //send - the buffer size must be adjusted, it's a sample
}

/* Client side */
int main () {
Object o2;
stringstream ss2;
char buffer[20];
string temp;

read (socket, buffer, 20);  //receive
temp.assign(buffer);
ss << temp;
ss >> o2;   //unserialize
}

I'm not sure if is necessary convert to string before to serialize (ss << o), maybe is possible directly from char.

Upvotes: 0

Matthieu M.
Matthieu M.

Reputation: 299810

My first question will be: do you want serialization or messaging ?

It might seem stupid at first, since you asked for serialization, but then I have always distinguished the two terms.

  • Serialization is about taking a snapshot of your memory and restoring it later on. Each object is represented as a separate entity (though they might be composed)
  • Messaging is about sending information from one point to another. The message usually has its own grammar and may not reflect the organization of your Business Model.

Too often I've seen people using Serialization where Messaging should have been used. It does not mean that Serialization is useless, but it does mean that you should think ahead of times. It's quite difficult to alter the BOM once you have decided to serialize it, especially if you decide to relocate some part of information (move it from one object to another)... because how then are you going to decode the "old" serialized version ?

Now that that's been cleared up...

... I will recommend Google's Protocol Buffer.

You could perfectly rewrite your own using the STL, but you would end up doing work that has already been done, and unless you wish to learn from it, it's quite pointless.

One great thing about protobuf is that it's language agnostic in a way: ie you can generate the encoder/decoder of a given message for C++, Java or Python. The use of Python is nice for message injection (testing) or message decoding (to check the output of a logged message). It's not something that would come easy were you to use the STL.

Upvotes: 5

Travis Gockel
Travis Gockel

Reputation: 27633

You can serialize with anything. All serialization means is that you are converting the object to bytes so that you can send it over a stream (like an std::ostream) and read it with another (like an std::istream). Just override operator <<(std::ostream&, const T&) and operator >>(std::istream&, T&) where T is each of your types. And all the types contained in your types.

However, you should probably just use an already-existing library (Boost is pretty nice). There are tons of things that a library like Boost does for you, like byte-ordering, taking care of common objects (like arrays and all the stuff from the standard library), providing a consistent means of performing serialization and tons of other stuff.

Upvotes: 7

Related Questions