3

I need to create TCP chat with C++ clients and Python server(already started), I have messages in c++ class like

class Message{
public:
uint64 utc_time;
uint64 token;
string content;
};

I am sending this from client to server, on server I have priority queue by utc_time and need to broadcast to others. My question is how to serialize this, which format to use so to avoid any cross language dependencies on size type size ? (maybe is going to be more meta data in future so need kind a little generic) ? Can anyone give me advice which format to use for serialization(or to flush only like bytes) ?

class Persistent:
public:
    Persistent(int sz):objSize(sz){}
    void write(std::ostream& out)const{out.write((char*)this, objSize);}
    void read(std::istream& in){in.read((char*)this, objSize);}
private:
    int objSize;
};

I thought of other possibility to have deserializator in c++ on server and call from python if that is possible. Any elegant solution to this problem ?

PaolaJ.
  • 10,872
  • 22
  • 73
  • 111
  • 6
    Have you looked at [Protocol Buffers](http://code.google.com/p/protobuf/), [Thrift](http://thrift.apache.org/), [JSON](http://json.org/), or any of the hundred other common solutions suggested by your search engine of choice? – willglynn Dec 04 '12 at 22:41
  • 3
    Language dependencies aren't the problem, different machines i.e. word size, endianness, etc., are. Use a known solution as suggested above rather than reinvent this wheel. Just make sure the solution handles python & c++. Probably not a problem. – Duck Dec 04 '12 at 22:43
  • 1
    Google protocol buffers http://code.google.com/p/protobuf/ – gvd Dec 04 '12 at 23:11
  • @willglynn I have JSON already but I think that problem can be when I send two messages from same, or receive couple messages from server(every message is JSON) how to know where is the end of one if all I got is byte array. ( Maybe to use array but I will in 99% send only one, and that 1% is critical) – PaolaJ. Dec 05 '12 at 00:47
  • 1
    @willglynn: "*how to know where is the end of one if all I got is byte array.*" That's called "parsing JSON." Whatever tool you use to parse it will know where the end is. – Nicol Bolas Dec 05 '12 at 00:57
  • @PaolaJ. This was an answer I wrote for a slightly different question, but it may give you some background on network protocols in general. As other have said I would go with a framework, but this may help you understand what the framework is doing underneath the hood: http://stackoverflow.com/a/285986/34329 – grieve Dec 07 '12 at 16:59

3 Answers3

4

If you really want to go cross language and cross platform without having to worry about where the message ends, have a look at the combination of Google Protobuf and ZeroMQ.

When using regular sockets you would first read the size of the message (you would prepend this) and then you would know from where to where the byte-array is a complete message.

Example protobuf + zmq usage:

message Message {
    optional uint64 utc_time = 1;
    required uint64 token = 2;
    optional string content = 3;
}

Use the protobuf compiler to generate C++ code (or ruby/python/etc).

To use it in your code:

#include <Message.pb.h>

Message msg;
msg.set_token(1);
msg.set_content("Hello world");

To send it using zmq:

std::string serialized = msg.SerializeAsString();
zmq::message_t reply(serialized.size());
memcpy(reply.data(), serialized.data(), serialized.size());
zmq_socket.send(reply);

To receive it using zmq:

zmq::message_t request;
zmq_socket.recv(&request); // blocking
Message recv_msg;
recv_msg.ParseFromArray(request.data(), request.size());
gvd
  • 1,823
  • 13
  • 18
1

Using ZeroMQ is a good start since it takes care of all the transport work for you. The best way to serialize depends on the kind of work you're doing. Since you're doing a chat application, efficiency is not a concern, so I'd use a self-describing text format, which is simplest to debug, trace, log, and use. Anything like protobufs or msgpack is going to be extra work for no measurable reward. You can use XML, JSON, HTTP-style headers, name=value pairs, etc.

When you get to making really high-volume messages (hundreds of thousands per second) or really large ones (over say 1K bytes), then you can start to think of different ways to reduce the message size. I'd personally recommend sticking with the simplest possible text format until you do have a performance issue, then switching to the most efficient binary format for the cases that need it. But not in a chat app...

Pieter Hintjens
  • 6,599
  • 1
  • 24
  • 29
  • I disagree that it's more work. The JSon or XML also needs to be parsed. Serializing/Deserializing protobuf messages is build in. You can even just send it as text (calling ```.DebugString()``` on the object) and parse that into a protobuffer again. You handle the messages as regular objects without having to write any of the accessor code yourself. – gvd Dec 06 '12 at 19:59
  • @gvd: But that makes it harder to debug the protocol on the wire using TCP/IP sniffing tools. – jmucchiello Dec 10 '12 at 17:20
  • @jmucchiello true in the sense that it's not human readable, but if you have to do that you are doing something wrong to begin with. Add some unit tests. You can call a ```.PrintDebugString()``` on a protobuf before sending it and right after receiving it to check if the content is the same. – gvd Dec 10 '12 at 17:52
1

I like to use JSON, assuming you have a good buffered interface to the socket and a JSON parser based on streams. The nice thing about JSON is you don't need to specify the length of each message. A properly written JSON parser can tell when it hits the end of the "object". So your reader object can just parse the JSON as it comes over the wire and when you reach the end of the initial object, return it to the system as one message.

If JSON is overkill for your data, there's always plain text. Most of the internet runs on plain text (POP, IMAP, HTTP, FTP, etc.). And that's because plain text is the easiest thing to using cross-platform/cross-language.

jmucchiello
  • 18,754
  • 7
  • 41
  • 61
  • Plain text for the command structure is still easiest. Worse case scenario with Unicode strings, you can send them as hex dumps (or base64 if you prefer). But the simple beauty of HELO cannot be ignored. – jmucchiello Dec 10 '12 at 17:18
  • I understand what you are saying, but "easy" is subjective. 'H' is simpler than "HELO" for example, but I couldn't argue that either is easier without more context. – grieve Dec 10 '12 at 19:12