C++ design - Network packets and serialization

I have, for my game, a Packet class, which represents network packet and consists basically of an array of data, and some pure virtual functions

I would then like to have classes deriving from Packet, for example: StatePacket, PauseRequestPacket, etc. Each one of these sub-classes would implement the virtual functions, Handle(), which would be called by the networking engine when one of these packets is received so that it can do it's job, several get/set functions which would read and set fields in the array of data.

So I have two problems:

  1. The (abstract) Packet class would need to be copyable and assignable, but without slicing, keeping all the fields of the derived class. It may even be possible that the derived class will have no extra fields, only function, which would work with the array on the base class. How can I achieve that?
  2. When serializing, I would give each sub-class an unique numeric ID, and then write it to the stream before the sub-class' own serialization. But for unserialization, how would I map the read ID to the appropriate sub-class to instanciate it?

If anyone want's any clarifications, just ask.

-- Thank you


Edit: I'm not quite happy with it, but that's what I managed:

Packet.h: http://pastebin.com/f512e52f1 Packet.cpp: http://pastebin.com/f5d535d19 PacketFactory.h: http://pastebin.com/f29b7d637 PacketFactory.cpp: http://pastebin.com/f689edd9b PacketAcknowledge.h: http://pastebin.com/f50f13d6f PacketAcknowledge.cpp: http://pastebin.com/f62d34eef

If someone has the time to look at it and suggest any improvements, I'd be thankful.


Yes, I'm aware of the factory pattern, but how would I code it to construct each class? A giant switch statement? That would also duplicade the ID for each class (once in the factory and one in the serializator), which I'd like to avoid.

Answers


For copying you need to write a clone function, since a constructor cannot be virtual:

virtual Packet * clone() const = 0;

Which each Packet implementation implement like this:

virtual Packet * clone() const {
    return new StatePacket(*this);
}

for example for StatePacket. Packet classes should be immutable. Once a packet is received, its data can either be copied out, or thrown away. So a assignment operator is not required. Make the assignment operator private and don't define it, which will effectively forbid assigning packages.

For de-serialization, you use the factory pattern: create a class which creates the right message type given the message id. For this, you can either use a switch statement over the known message IDs, or a map like this:

struct MessageFactory {
    std::map<Packet::IdType, Packet (*)()> map;

    MessageFactory() {
        map[StatePacket::Id] = &StatePacket::createInstance;
        // ... all other
    }

    Packet * createInstance(Packet::IdType id) {
        return map[id](); 
    }
} globalMessageFactory;

Indeed, you should add check like whether the id is really known and such stuff. That's only the rough idea.


Need Your Help

running this code halts my while loop

php mysql select

$q1 = mysql_query("select in_time, out_time from $att_tbl where fk_eid = '$e_id' and a_date = '$dts'");

Difference between a git commit and the working directory?

git-diff

The git-diff manual pages says that git diff is used to

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.