1 // ANNA - Anna is Not 'N' Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #ifndef anna_comm_comm_hpp
38 #define anna_comm_comm_hpp
42 Proporciona las clases necesarias para la comunicacion entre procesos.
44 A continuacion presentamos el codigo de ejemplo de un servidor aritmetico. Recibe dos operadores y una
45 operacion (+,-,*,/) y devuelve el resultado de la operacion. Para estudiar los sistemas de control de
46 congestion hemos incorporado la posibilidad de que el servidor espere un numero de segundo indeterminado
47 antes de dar la respuesta.
54 #include <anna/comm/h>
56 #include <test.Request.h>
57 #include <test.Response.h>
62 //-----------------------------------------------------------------------------------------
63 // Define el comunicador de nuestra aplicacin.
65 // Las peticiones y respuestas van codificadas mediante un comm::Codec pero podriamos
66 // haber utilizado cualquier otro medio de codificacin ya que la capa de transporte
67 // es totalmente independiente del contenido del mensaje.
69 // De cara a la capa de transporte lo unico que importa es el cliente y el servidor
70 // codifiquen/decodifiquen de la misma forma.
71 //-----------------------------------------------------------------------------------------
72 class MyCommunicator : public comm::Communicator {
76 void setDelay (const Millisecond &delay) throw () { a_delay = delay; }
83 void eventReceiveMessage (comm::ClientSocket &, const DataBlock& data)
84 throw (RuntimeException);
87 class ArithmeticServer : public comm::Application {
92 MyCommunicator a_communicator;
93 comm::ServerSocket* a_serverSocket;
95 void initialize () throw (RuntimeException);
96 void run () throw (RuntimeException);
100 using namespace anna::comm;
102 int main (int argc, const char** argv)
104 CommandLine& commandLine (CommandLine::instantiate ());
105 ArithmeticServer app;
110 commandLine.initialize (argv, argc);
111 commandLine.verify ();
113 Logger::setLevel (Logger::Debug);
114 Logger::initialize ("arithmeticServer", new anna::TraceWriter ("file.trace", 4048000));
118 catch (Exception& ex) {
119 cout << ex.asString () << endl;
125 ArithmeticServer::ArithmeticServer () :
126 Application ("arithmeticServer", "Servidor de operaciones aritmeticas", "1.0")
128 CommandLine& commandLine (CommandLine::instantiate ());
130 commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones");
131 commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender");
132 commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacio");
133 commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false);
134 commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos");
137 //-----------------------------------------------------------------------------------------
138 // Inicializa el servidor de sockets.
139 //-----------------------------------------------------------------------------------------
140 void ArithmeticServer::initialize ()
141 throw (RuntimeException)
143 CommandLine& cl (CommandLine::instantiate ());
145 int port = cl.getIntegerValue ("p");
146 const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a")));
148 a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"));
151 //-----------------------------------------------------------------------------------------
152 // Atiende las peticiones.
153 // Cuando hay un nuevo mensaje invocar�a Communicator::eventReceiveMessage
154 //-----------------------------------------------------------------------------------------
155 void ArithmeticServer::run ()
156 throw (RuntimeException)
158 CommandLine& cl (CommandLine::instantiate ());
160 a_communicator.attach (a_serverSocket);
161 a_communicator.setDelay (cl.getIntegerValue ("d"));
163 CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit"));
165 a_communicator.accept ();
168 //-----------------------------------------------------------------------------------------
169 // Manejador de peticiones.
170 // Calcular�la operacin solicitada y devolver�el resultado.
172 // clientSocket: Socket cliente por el que podemos responder a la peticin.
173 // transport: Instancia del transporto que ha interpretado el mensaje (getMessage).
174 //-----------------------------------------------------------------------------------------
175 void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const DataBlock& data)
176 throw (RuntimeException)
178 LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION));
180 static int messageCounter = 0;
181 static int successCounter = 0;
185 CongestionController& congestionController = CongestionController::instantiate ();
189 if (congestionController.getAdvice (clientSocket) == CongestionController::Advice::Discard)
194 int random = rand () % (a_delay / 10);
195 int sign = rand () % 2;
200 anna::functions::sleep (a_delay + random);
202 a_request.decode (data);
204 a_response.x = a_request.x;
205 a_response.y = a_request.y;
207 switch (a_response.op = a_request.op) {
209 a_response.result = a_request.x + a_request.y;
212 a_response.result = a_request.x - a_request.y;
215 a_response.result = a_request.x * a_request.y;
218 a_response.result = (a_request.y != 0) ? (a_request.x / a_request.y): 0;
223 string msg = anna::functions::asString (
224 "%d %c %d = %d", a_request.x, a_request.op, a_request.y, a_response.result
226 Logger::debug (msg, ANNA_FILE_LOCATION);
230 clientSocket.send (a_response.code ());
232 catch (Exception& ex) {
238 El siguiente ejemplo muestra un cliente correspondiente al servidor anterior, que lanza un numero
239 determinado de peticiones por segundo.
247 #include <anna/comm/h>
249 #include <anna.timex.Engine.h>
250 #include <anna.timex.Clock.h>
252 #include <test.Response.h>
253 #include <test.Request.h>
255 class Sender : public timex::Clock {
257 Sender () : Clock ("Sender", 250), a_messageBySecond (0), a_nquarter (0) {;}
259 void setMessageBySecond (const int messageBySecond) throw () { a_messageBySecond = messageBySecond; }
262 int a_messageBySecond;
264 test::Request a_request;
266 void tick () throw (RuntimeException);
269 //-----------------------------------------------------------------------------------------
270 // Define el comunicador de nuestra aplicacin.
272 // Las peticiones y respuestas van codificadas mediante un comm::Codec pero podriamos
273 // haber utilizado cualquier otro medio de codificacin ya que la capa de transporte
274 // es totalmente independiente del contenido del mensaje.
275 //-----------------------------------------------------------------------------------------
276 class MyCommunicator : public Communicator {
278 MyCommunicator () : Communicator () {;}
281 test::Response a_response;
283 void eventReceiveMessage (ClientSocket &, const DataBlock&)
284 throw (RuntimeException);
287 class HeavyClient : public anna::comm::Application {
291 Server* getServer () const throw () { return a_server; }
294 MyCommunicator a_communicator;
295 timex::Engine a_timeController;
299 void initialize () throw (RuntimeException);
300 void run () throw (RuntimeException);
305 int main (int argc, const char** argv)
307 CommandLine& commandLine (CommandLine::instantiate ());
313 commandLine.initialize (argv, argc);
314 commandLine.verify ();
316 Logger::setLevel (Logger::Debug);
317 Logger::initialize ("arithmeticClient", new TraceWriter ("file.trace", 1048000));
321 catch (Exception& ex) {
322 cout << ex.asString () << endl;
328 HeavyClient::HeavyClient () :
329 Application ("arithmeticClient", "Cliente de operaciones aritmeticas", "1.0"),
331 a_timeController ((Millisecond)10000, (Millisecond)250)
333 CommandLine& commandLine (CommandLine::instantiate ());
335 commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas.");
336 commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas.");
337 commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo");
341 //-----------------------------------------------------------------------------------------
342 // Inicializa las conexiones usadas por la aplicacin.
344 // Primero establece los datos para la conexin con el servidor aritm�ico y luego
345 // establece los datos del socket servidor necesario para atender respuestas y aceptar
346 // nuevas conexiones de procesos clientes (que no ser�el caso).
347 // Configura el men para que trabaje con el comunicador de esta aplicacin.
348 //-----------------------------------------------------------------------------------------
349 void HeavyClient::initialize ()
350 throw (RuntimeException)
352 CommandLine& cl (CommandLine::instantiate ());
354 Network& network = Network::instantiate ();
356 Host* host = network.find ("host000");
357 host->assign (network.find (Device::asAddress (cl.getValue ("a"))));
358 a_server = host->createServer ("rawServer", cl.getIntegerValue ("p"), true);
359 a_sender.setMessageBySecond (cl.getIntegerValue ("n"));
362 //-----------------------------------------------------------------------------------------
363 // Activa el reloj que dara el pulso para enviar los mensajes al servidor y comienza a
364 // atender las peticiones.
365 //-----------------------------------------------------------------------------------------
366 void HeavyClient::run ()
367 throw (RuntimeException)
369 a_timeController.activate (a_sender);
371 a_communicator.accept ();
374 //-----------------------------------------------------------------------------------------
375 // Manejador de respuesta.
377 // clientSocket: Socket cliente por el que podemos responder a la peticin.
378 // transport: Instancia del transporto que ha interpretado el mensaje (getMessage).
379 //-----------------------------------------------------------------------------------------
380 void MyCommunicator::eventReceiveMessage (ClientSocket&, const DataBlock& data)
381 throw (RuntimeException)
383 a_response.decode (data);
385 string msg = anna::functions::asString (
386 "%d %c %d = %d", a_response.x, a_response.op, a_response.y, a_response.result
388 Logger::information (msg, ANNA_FILE_LOCATION);
392 throw (RuntimeException)
394 Server* server = static_cast <HeavyClient&> (anna::app::functions::getApp ()).getServer ();
395 Communicator* communicator = anna::app::functions::component <Communicator> (ANNA_FILE_LOCATION);
397 int maxn = a_messageBySecond / 4;
399 if (++ a_nquarter == 4) {
400 maxn += a_messageBySecond % 4;
407 maxn = rand () % maxn;
409 for (int n = 0; n < maxn; n ++) {
411 a_request.x = rand () % 1000;
412 a_request.y = rand () % 1000;
415 server->send (a_request.code ());
417 catch (RuntimeException& ex) {
426 El ejecutable debera enlazarse con las librerias:
432 El <b>Packet Header</b> es anna/comm/h
438 #include <anna/comm/Application.hpp>
439 #include <anna/comm/Buffer.hpp>
440 #include <anna/comm/ClientSocket.hpp>
441 #include <anna/comm/Codec.hpp>
442 #include <anna/comm/Communicator.hpp>
443 #include <anna/comm/CongestionController.hpp>
444 #include <anna/comm/DatagramSocket.hpp>
445 #include <anna/comm/Device.hpp>
446 #include <anna/comm/Delivery.hpp>
447 #include <anna/comm/DirectTransport.hpp>
448 #include <anna/comm/Host.hpp>
449 #include <anna/comm/LargeBinaryCodec.hpp>
450 #include <anna/comm/LiteTransport.hpp>
451 #include <anna/comm/Message.hpp>
452 #include <anna/comm/Network.hpp>
453 #include <anna/comm/INetAddress.hpp>
454 #include <anna/comm/Transport.hpp>
455 #include <anna/comm/Server.hpp>
456 #include <anna/comm/Service.hpp>
457 #include <anna/comm/ServerAllocator.hpp>
458 #include <anna/comm/ServerSocket.hpp>
459 #include <anna/comm/handler/BinderSocket.hpp>
460 #include <anna/comm/Service.hpp>
461 #include <anna/comm/Status.hpp>
462 #include <anna/comm/Variable.hpp>
463 #include <anna/comm/Receiver.hpp>
464 #include <anna/comm/ReceiverFactory.hpp>
465 #include <anna/comm/ReceiverFactoryImpl.hpp>
466 #include <anna/comm/RoundRobinDelivery.hpp>
467 #include <anna/comm/ByRangeDelivery.hpp>
468 #include <anna/comm/IndexedDelivery.hpp>
470 using namespace anna::comm;