2

I have for quite some time now tried to find a good way to serialize or send a state object over tcp socket. My problem is that I am not able to use any 3. party libraries like boost.

My state object contains multiple objects. The most essential is that it got some objects and a vector of objects, but no pointers (eg. probably no deep copying, if vector dont require this).

To my question: Since I cant use boost or any other libraries, what is the best way to send a object with objects over socket? I have been thinking that I probably could make a copy constructor and send this to a stream, but I am not quite sure about the consequences of doing this.

larhauga
  • 45
  • 1
  • 5
  • The tool you need to use is called (de)serialization. Try searching SO, you will find a lot of useful answers (like in here: http://stackoverflow.com/questions/234724/is-it-possible-to-serialize-and-deserialize-a-class-in-c) – Nemanja Boric Apr 21 '13 at 10:09
  • Yep, I will need to serialize the objects, but I cant use libraris like Boost like the link you referred to. But in this I am wondering how the best way to serialize the objects without the usage of said libraries :) – larhauga Apr 21 '13 at 10:45

1 Answers1

2

Define (de-)serialization functions for your data types.

For example, if you have something like:

class MyClass
{
public: 
    int field_a;
    int field_b;
    std::string string;
    ...
};
typedef std::vector<MyClass> MyVector;

You can define the following:

void write(int fd, const MyClass &arg)
{
    // either convert arg to byte array and write it, or write field by field
    // here we write it field by field
    write_int(fd, arg.field_a);
    write_int(fd, arg.field_b);
    write_string(fd, arg.string);
}

void write(int fd const MyVector &arg)
{
    size_t size = arg.size();
    ::write(fd, &size, sizeof(size)); // beware: machine-dependent code
    for (MyVector::const_iterator it = arg.begin(); it != arg.end(); it++)
    {
        write(*it);
    }
}

Helper functions:

void write_int(int fd, int arg)
{
    write(fd, &arg, sizeof(int));
}

void write_string(int fd, const std::string &str)
{
    size_t len = str.length();

    write(fd, &len, sizeof(len)); // string length go first
    write(fd, str.data(), len); // write string data
}

And reading:

MyClass readMC(int fd)
{
    // read MyClass data from stream, parse it
    int f1, f2;
    std::string str;

    read_int(fd, f1);
    read_int(fd, f2);

    read_string(fd, str)

    return MyClass(f1, f2, str);
}

void read(int fd, MyVector &arg)
{
    size_t size;
    size_t i;

    read(fd, &size, sizeof(size)); // read number of elements;
    arg.reserve(size);
    for (i = 0; i < size; i++)
    {
        arg.push_back(readMC(fd));
    }
}

Helper functions:

void read_int(int fd, int &res);
{
    read(fd, &res, sizeof(res));
}

void read_string(int fd, std::string &string)
{
    size_t len;
    char *buf;

    read(fd, &len, sizeof(len));
    buf = new char[len];
    read(fd, buf, len);
    string.asssign(buf, len);
    delete []buf;
}
Valeri Atamaniouk
  • 5,125
  • 2
  • 16
  • 18
  • That sounds like a plan, but I have some questions to your code. What is the `int fd`? You say that i can convert arg to byte array or field by field. How exacly would i do this in the write function so that I could parse this on read. Is there a good way to output this to like a ostream? – larhauga Apr 21 '13 at 10:37
  • fd is a file descriptor, used to access the socket connection. – Etherealone Apr 21 '13 at 11:00
  • @larhauga it is simple. sockets transfer bytes. so you make your objects to look as a sequence of bytes and back – Valeri Atamaniouk Apr 21 '13 at 13:05