![]() |
||||||||
|
|
||||||||
Attaching the data is a simple matter of passing a bitstream object to the connect function.
// assuming the initialized client from the previous chapter here // prepare bitstream ZCom_BitStream *password = new ZCom_BitStream(); password->addString("let_me_in"); // prepare address ZCom_Address server_addr; server_addr.setAddress( eZCom_AddressUDP, 0, "localhost:10000"); // connect ZCom_ConnID connection_id = client->ZCom_Connect(server_addr, password); password = NULL;
The first parameter is _id, which holds the id of the incoming connection. When the connection is accepted by the server, this _id can be used to act on the connection as long as it is alive.
The second parameter is _request. It is a reference to a bitstream, and this bitstream contains whatever the client has attached to the connection request. The goal is to accept the connection only when the correct password has been attached.
The following code is meant to replace the implementation presented in Step 3.1 Handling Connection Requests from The Server.
class Server : public ZCom_Control { bool ZCom_cbConnectionRequest(ZCom_ConnID _id, ZCom_BitStream &_request, ZCom_BitStream &_reply ) { printf("A client requested connection - the new id is [%d].\n", _id); // get the password const char *password = _request.getStringStatic(); // compare it if (password && strlen(password) > 0 && strcmp("let_me_in", password) == 0) { printf("Connection Accepted.\n"); _reply.addString("Password Correct."); // accept connection return true; } else { _reply.addString("Password Wrong."); printf("Connection Denied.\n"); // deny connection return false; } } // all other callback methods omitted here };
As you can see, the _reply bitstream in this callback can be filled with data. This data will be received by the client in the ZCom_cbConnectResult() callback.
class Client : public ZCom_Control { virtual void ZCom_cbConnectResult( ZCom_ConnID _id, eZCom_ConnectResult _result, ZCom_BitStream &_reply ) { if (_result == eZCom_ConnAccepted) printf("Connection established. The reply was: %s\n", _reply.getStringStatic()); else { printf("Connection failed. The reply was: %s\n", _reply.getStringStatic()); return; } // if we get here, the connection was accepted // create a bitstream for the request ZCom_BitStream *therequest = new ZCom_BitStream(); // add the number 9 as a 4 bit value therequest->addInt(9, 4); // send the data to the server ZCom_sendData(_id, therequest); // we are not allowed to delete the stream after it has been sent therequest = NULL; } // all other callback methods omitted here
This adds two things to the previous implementation. First, the content of the _reply bitstream is read and printed to the console. The bitstream has to contain a string, otherwise getStringStatic() will return NULL. Second, and most importantly, we send the request for the "Hello from Server" string. This is done by creating a new bitstream object, filling it with the number 9 (meaning we want the string 9 times) and then sending the bitstream to the server.
The number is sent as a 4 bit value. That means, the maximum sendable number would be 15. The server will expect a 4 bit value, so it is not possible to simply increase the amount of bits only on the client, as the server will try to read exactly 4 bits. If more bits are needed, the change needs to be done on server and client alike.
ZCom_sendData() sends the data to the connection with the id stored in _id. This happens to be the connection for which we just received the connectresult notification, the connection initially requested with the password "let_me_in". The value stored in _id is also equal to the value stored in connection_id previously declared here: Step 1 (Client): Attaching Data To The Connection Request.
The server implementation for this callback will read an integer as a 4 bit value from the incoming data (because that is what the client should be sending) and then it will send the string "Hello from Server" the read amount of times back to the client.
This code replaces the previously empty callback ZCom_cbDataReceived() in the server class (The Server).
class Server : public ZCom_Control { void ZCom_cbDataReceived(ZCom_ConnID _id, ZCom_BitStream &_data) { // read 4 bit integer int number = _data.getInt(4); printf("The client requested our message %d number of times.\n", number); // create a bitstream for the message ZCom_BitStream *message = new ZCom_BitStream(); message->addString("Hello from Server"); // send it as often as requested while (number--) ZCom_sendData(_id, message->Duplicate()); // we made a copy for every send, so the original bitstream is unused // and can be deleted delete message; } // all other callback methods omitted here };
The server sends the message 9 times (because we sent a 9 in Step 3 (Client): Receiving The Reply And Sending Data), and so the callback will get called 9 times, too.
class Client : public ZCom_Control { void ZCom_cbDataReceived(ZCom_ConnID _id, ZCom_BitStream &_data) { printf("Received a string: %s\n", _data.getStringStatic()); } // all other callback methods omitted here };
#include <stdlib.h> #include <stdio.h> #include <zoidcom.h> class Server : public ZCom_Control { // someone tries to connect bool ZCom_cbConnectionRequest(ZCom_ConnID _id, ZCom_BitStream &_request, ZCom_BitStream &_reply ) { printf("A client requested connection - the new id is [%d].\n", _id); // get the password const char *password = _request.getStringStatic(); // compare it if (password && strlen(password) > 0 && strcmp("let_me_in", password) == 0) { printf("Connection Accepted.\n"); _reply.addString("Password Correct."); // accept connection return true; } else { _reply.addString("Password Wrong."); printf("Connection Denied.\n"); // deny connection return false; } } // someone has connected void ZCom_cbConnectionSpawned( ZCom_ConnID _id ) { printf("New connection with id [%d]\n", _id); } // someone has disconnected void ZCom_cbConnectionClosed( ZCom_ConnID _id, eZCom_CloseReason _reason, ZCom_BitStream &_reasondata ) { printf("Connection with id [%d] closed\n", _id); } // someone has sent data void ZCom_cbDataReceived(ZCom_ConnID _id, ZCom_BitStream &_data) { // read 4 bit integer int number = _data.getInt(4); printf("The client requested our message %d number of times.\n", number); // create a bitstream for the message ZCom_BitStream *message = new ZCom_BitStream(); message->addString("Hello from Server"); // send it as often as requested int i = 1; while (number--) { printf("Sending #%d\n", i++); ZCom_sendData(_id, message->Duplicate()); } // we made a copy for every send, so the original bitstream is unused // and can be deleted delete message; } // currently irrelevant callbacks have empty bodies void ZCom_cbConnectResult( ZCom_ConnID _id, eZCom_ConnectResult _result, ZCom_BitStream &_reply ) {} bool ZCom_cbZoidRequest( ZCom_ConnID _id, zU8 _requested_level, ZCom_BitStream &_reason ) {return false;} void ZCom_cbZoidResult( ZCom_ConnID _id, eZCom_ZoidResult _result, zU8 _new_level, ZCom_BitStream &_reason ) {} void ZCom_cbNodeRequest_Dynamic( ZCom_ConnID _id, ZCom_ClassID _requested_class, ZCom_BitStream *_announcedata, eZCom_NodeRole _role, ZCom_NodeID _net_id ) {} void ZCom_cbNodeRequest_Tag( ZCom_ConnID _id, ZCom_ClassID _requested_class, ZCom_BitStream *_announcedata, eZCom_NodeRole _role, zU32 _tag ) {} bool ZCom_cbDiscoverRequest( const ZCom_Address &_addr, ZCom_BitStream &_request, ZCom_BitStream &_reply ) {return false;} void ZCom_cbDiscovered( const ZCom_Address & _addr, ZCom_BitStream &_reply ) {} }; int main() { // initialize Zoidcom ZoidCom* zcom = new ZoidCom("zoidcom.log"); if (!zcom || !zcom->Init()) exit(255); // make instance of our Server class Server *server = new Server(); server->ZCom_setDebugName("Server"); // this creates and initializes the network sockets // true = use udp socket, 10000 = the UDP port to use, 0 = no internal socket bool result = server->ZCom_initSockets(true, 10000, 0); // if result is false, Zoidcom had problems while initializing if (!result) exit(255); while ( true ) { // tell the server to process incoming data printf("Processing input...\n"); server->ZCom_processInput(); // tell the server to process outgoing data printf("Processing output...\n"); server->ZCom_processOutput(); // let the program sleep for 0 msecs zcom->Sleep(1); } delete server; delete zcom; return 0; };
#include <stdlib.h> #include <stdio.h> #include <zoidcom.h> bool exit_now = false; class Client : public ZCom_Control { virtual void ZCom_cbConnectResult( ZCom_ConnID _id, eZCom_ConnectResult _result, ZCom_BitStream &_reply ) { if (_result == eZCom_ConnAccepted) printf("Connection established. The reply was: %s\n", _reply.getStringStatic()); else { printf("Connection failed. The reply was: %s\n", _reply.getStringStatic()); return; } // if we get here, the connection was accepted printf("Requesting 9 strings...\n"); // create a bitstream for the request ZCom_BitStream *therequest = new ZCom_BitStream(); // add the number 9 as a 4 bit value therequest->addInt(9, 4); // send the data to the server ZCom_sendData(_id, therequest); // therequest has been given to Zoidcom and may not be deleted therequest = NULL; } void ZCom_cbConnectionClosed( ZCom_ConnID _id, eZCom_CloseReason _reason, ZCom_BitStream &_reasondata ) { printf("Connection to server closed. Exiting...\n"); exit_now = true; } // data was received void ZCom_cbDataReceived(ZCom_ConnID _id, ZCom_BitStream &_data) { printf("Received a string: %s\n", _data.getStringStatic()); } bool ZCom_cbConnectionRequest( ZCom_ConnID _id, ZCom_BitStream &_request, ZCom_BitStream &_reply ){return false;} void ZCom_cbConnectionSpawned( ZCom_ConnID _id ) {} bool ZCom_cbZoidRequest( ZCom_ConnID _id, zU8 _requested_level, ZCom_BitStream &_reason ) {return false;} void ZCom_cbZoidResult( ZCom_ConnID _id, eZCom_ZoidResult _result, zU8 _new_level, ZCom_BitStream &_reason ) {} void ZCom_cbNodeRequest_Dynamic( ZCom_ConnID _id, ZCom_ClassID _requested_class, ZCom_BitStream *_announcedata, eZCom_NodeRole _role, ZCom_NodeID _net_id ) {} void ZCom_cbNodeRequest_Tag( ZCom_ConnID _id, ZCom_ClassID _requested_class, ZCom_BitStream *_announcedata, eZCom_NodeRole _role, zU32 _tag ) {} bool ZCom_cbDiscoverRequest( const ZCom_Address &_addr, ZCom_BitStream &_request, ZCom_BitStream &_reply ) {return false;} void ZCom_cbDiscovered( const ZCom_Address & _addr, ZCom_BitStream &_reply ) {} }; int main() { // initialize Zoidcom ZoidCom* zcom = new ZoidCom("zoidcom.log"); if (!zcom || !zcom->Init()) exit(255); // make instance of our Client class Client *client = new Client(); client->ZCom_setDebugName("Client"); // this creates and initializes the network sockets // true = use udp socket, 0 = let OS choose UDP port, 0 = no internal socket bool result = client->ZCom_initSockets(true, 0, 0); // if result is false, Zoidcom had problems while initializing if (!result) exit(255); // put this into a codeblock so that server_addr gets out of scope before // 'delete zcom;' get called (everything needs to be gone before the // ZoidCom object gets deleted) { printf("Connecting...\n"); // prepare bitstream ZCom_BitStream *password = new ZCom_BitStream(); password->addString("let_me_in"); // prepare address ZCom_Address server_addr; server_addr.setAddress( eZCom_AddressUDP, 0, "localhost:10000"); // connect ZCom_ConnID connection_id = client->ZCom_Connect(server_addr, password); password = NULL; } while ( !exit_now ) { // tell the client to process incoming data printf("Processing input...\n"); client->ZCom_processInput(); // tell the client to process outgoing data printf("Processing output...\n"); client->ZCom_processOutput(); // give up remaining cpu time zcom->Sleep(1); } delete client; delete zcom; return 0; };
1.4.6-NO