In this test we will create a chain of plugins on the server, and on the client the nested wrapping should be unpacked correctly.
The first plugin is the same as in the previous excample, it aggregates packets into one large packet.
#ifndef AGGR_PLUGIN_H
#define AGGR_PLUGIN_H
#include <map>
#include "../Ganef/common/plugin.h"
template<class PacketType>
class AggregationPlugin : public Plugin<PacketType>
{
private:
std::map<unsigned int, PacketType *> aggr_packs;
typedef typename std::map<unsigned int, PacketType *>::iterator MapIterator;
public:
virtual const unsigned int getUniqueId() const
{
return 0x12345;
}
virtual void pack(PacketType * packet)
{
if(aggr_packs.find(packet->getUserID()) == aggr_packs.end())
{
std::cout << "Creating new Aggregation packet for client: " << packet->getUserID() << std::endl;
aggr_packs[packet->getUserID()] = PacketType::createPluginPacket(this, packet);
}
aggr_packs[packet->getUserID()]->writeUInt32(packet->getSize());
aggr_packs[packet->getUserID()]->writePacket(packet);
delete packet;
}
virtual void unpack(PacketType * packet)
{
std::cout << "AggregationPlugin::unpack(" << packet << ")\n";
unsigned int psize;
while((psize = packet->readUInt32()) != 0)
{
PacketType * p = packet->readPacket(psize);
forwardUnpack(p);
}
delete packet;
}
virtual void onPurge()
{
MapIterator it;
for(it = aggr_packs.begin(); it != aggr_packs.end(); ++it)
{
PacketType * pack = it->second;
pack->writeUInt32(0);
std::cout << "Purging a packet of size: " << pack->getSize() << std::endl;
forwardPack(pack);
}
aggr_packs.clear();
}
};
#endif
The second plugin is a compression plugin using Zlib. This plugin does not need the onPurge(...) method, because it just forwards the compressed data-packet. The combination of these two plugins is smart, since packets are first collected into one large packet and then compressed to minimize bandwidth usage.
#ifndef ZLIB_PLUGIN_H
#define ZLIB_PLUGIN_H
#include <zlib.h>
#include "../Ganef/common/plugin.h"
template<class PacketType>
class ZlibPlugin : public Plugin<PacketType>
{
public:
virtual const unsigned int getUniqueId() const
{
return 0x711b;
}
virtual void pack(PacketType * packet)
{
packet->makeSendReady();
unsigned long have;
unsigned int outbuffsize = (packet->getSize() * 110) / 100 + 12;
unsigned char out[outbuffsize];
int ret = compress(out, &have, (unsigned char *)packet->getData(), packet->getSize());
PacketType * compressedpacket = PacketType::createPluginPacket(this, packet);
compressedpacket->writeUInt16(static_cast<unsigned short>(packet->getSize()));
compressedpacket->writeData(out, have);
delete packet;
std::cout << "ZLIB::pack(" << packet << ") ["<<packet->getSize()<<"->"<<have<<"]\n";
forwardPack(compressedpacket);
}
virtual void unpack(PacketType * packet)
{
unsigned long insize = packet->getDataSize() - sizeof(unsigned short);
unsigned long outsize = static_cast<unsigned long>(packet->readUInt16());
std::cout << "ZLIB::unpack(" << packet << ") ["<<insize<<"->"<<outsize<<"]\n";
unsigned char in[insize];
packet->readData(in, insize);
unsigned char dest[outsize];
int ret = uncompress(dest, &outsize, in, insize);
std::cout << "Actual size: " << outsize << ",ret:" << ret << std::endl;
PacketType * uncompressedpacket = new PacketType((char *)dest, outsize);
delete packet;
forwardUnpack(uncompressedpacket);
}
};
#endif
The client application is the same as the example before, except this one registeres both plugins.
#include <iostream>
#include <cstdlib>
#include "../Ganef/client/clientframework.h"
#include "../Ganef/client/clientdata.h"
#include "aggr_plugin.h"
#include "zlib_plugin.h"
class MyClientData : public ClientData
{
private:
int x,y;
public:
MyClientData(ClientFramework * f, ClientPacket * p) : ClientData(f,p),x(0),y(0)
{
x = p->readInt32();
y = p->readInt32();
std::cout << "Constructed a new object of class: MyClientData(";
std::cout << "ID:" << getFrameworkId() << ",";
std::cout << "x:"<<x<<",y:"<<y<<")" << std::endl;
}
virtual void updatePacket(ClientFramework * f, unsigned char updatetype, ClientPacket * packet)
{
}
static ClientData * constructMyClientData(ClientFramework * f, ClientPacket * p)
{
return new MyClientData(f,p);
}
};
class TestClientFramework : public ClientFramework
{
private:
bool is_running;
std::string server_hostname;
public:
TestClientFramework(const std::string & server_hostname) : ClientFramework(int(0)),server_hostname(server_hostname)
{
registerConstructor(0x424242, MyClientData::constructMyClientData);
}
~TestClientFramework()
{
};
protected:
virtual void writeHandshakeInitMessage( ClientPacket * fp ){}
virtual void onHandshakingDiscontinue( ClientPacket * fp ){}
virtual bool onHandshakeDescription( ClientPacket * fp, ClientPacket * reply )
{
return true;
}
virtual void onDisconnect( ) { std::cout << "Disconnected\n"; }
virtual void onConnect( ){ std::cout << "Connected\n"; }
public:
void mainLoop( )
{
registerPlugin(new AggregationPlugin<ClientPacket>());
registerPlugin(new ZlibPlugin<ClientPacket>());
std::cout << "Connecting to: " << server_hostname <<":"<< 8000<< std::endl;
initServerConnection(server_hostname, 8000);
is_running = true;
while(is_running)
{
keepAlive();
psleep(50);
}
}
};
int main(int argc, char *argv[])
{
std::string server_host("localhost");
if(argc > 1)
server_host = argv[1];
TestClientFramework app(server_host);
app.mainLoop();
}
The server in this test is almost the same as in the previous test, except the presending chain in this application contains two plugins. We also create a little more objects to better see the impact of the compression.
#include <iostream>
#include <cstdlib>
#include <vector>
#include "../Ganef/server/serverframework.h"
#include "aggr_plugin.h"
#include "zlib_plugin.h"
class MyServerData : public ServerData
{
private:
int x,y;
public:
MyServerData(ServerFramework * fw) : ServerData(fw, 10, false)
{
x = 200;
y = 150;
};
public:
virtual const unsigned int getClassId() const { return 0x424242; };
virtual void fillUpdatePacket(ServerPacket * packet, unsigned char type) const
{
switch(type)
{
case 5:
packet->writeInt32(x);
packet->writeInt32(y);
break;
}
}
virtual void fillCreateObjectPacket(ServerPacket * packet) const
{
packet->writeInt32(x);
packet->writeInt32(y);
}
virtual void clientPacket(Client * client, unsigned char type, ServerPacket * packet)
{
}
};
class TestServerFramework : public ServerFramework
{
public:
TestServerFramework() : ServerFramework(8000)
{
}
~TestServerFramework()
{
}
protected:
virtual bool onInitialHandshake(ServerPacket * handshake, ServerPacket * reply)
{
return true;
}
virtual void onClientConnected(Client * client)
{
std::cout << "Client: " << client->getId() << " connected\n";
setPreSendingChain("MyPluginChain");
std::map<unsigned int, ServerData *>::const_iterator it;
for(it = getServerDataObjects().begin(); it != getServerDataObjects().end(); ++it)
{
ServerData * s_data = it->second;
s_data->sendCreateObject(client);
}
purgeCurrentPreSendingChain();
setDefaultPreSendingChain();
}
virtual void onClientDisconnected(Client * client)
{
std::cout << "Client: " << client->getId() << " disconnected\n";
}
virtual Client * createClient(const ipaddress &addr, int port)
{
return new Client(this, addr, port);
}
public:
void mainLoop()
{
std::vector< Plugin<ServerPacket> * > chainlist;
chainlist.push_back(new AggregationPlugin<ServerPacket>());
chainlist.push_back(new ZlibPlugin<ServerPacket>());
registerPreSendingChain("MyPluginChain", chainlist);
std::cout << "TestServerFramework: Running\n";
std::vector<MyServerData *> mydata;
for(int i = 0; i < 25; i++)
mydata.push_back(new MyServerData(this));
int counter = 0;
while(true)
{
keepAlive();
if(counter++ % 100 == 0)
{
setPreSendingChain("MyPluginChain");
std::vector< MyServerData *>::const_iterator it;
for(it = mydata.begin(); it != mydata.end(); ++it)
{
MyServerData * s_data = *it;
s_data->sendUpdateToAll(5, false);
}
purgeCurrentPreSendingChain();
setDefaultPreSendingChain();
}
psleep(100);
}
}
};
int main(int argc, char *argv[])
{
try
{
TestServerFramework framework;
framework.start();
framework.mainLoop();
}
catch(FrameworkError *err)
{
std::cout << "FrameworkError:" << err->msg << std::endl;
}
catch(PacketError *err)
{
std::cout << "PacketError:" << err->msg << std::endl;
}
return EXIT_SUCCESS;
}
Generated on Mon Feb 6 12:24:58 2006 for Ganef by
1.4.4