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
38 Realiza peticiones automaticas sobre el servidor HTTP de operaciones aritmeticas.
40 La cadencia de envio de mensajes se establece mediante un temporizador.
41 Los operadores se calculan de forma aleatoria.
43 El servidor de este cliente: http_server.p o http_rserver.p
51 #include <anna/core/core.hpp>
52 #include <anna/app/functions.hpp>
53 #include <anna/comm/comm.hpp>
55 #include <anna/xml/DocumentMemory.hpp>
56 #include <anna/xml/Node.hpp>
57 #include <anna/xml/Parser.hpp>
59 #include <anna/timex/Engine.hpp>
60 #include <anna/timex/Clock.hpp>
62 #include <anna/http/Request.hpp>
63 #include <anna/http/Response.hpp>
64 #include <anna/http/Transport.hpp>
65 #include <anna/http/Handler.hpp>
67 static const Millisecond Resolution(250);
68 static const Millisecond Period(500);
69 static const Millisecond OneSecond(1000);
71 class Sender : public timex::Clock {
75 void setMessageBySecond (const int messageBySecond) throw () { a_messageByTick = messageBySecond / (OneSecond / Period); }
77 int getTxMessageCounter () const throw () { return a_txMessageCounter; }
80 struct Attribute { enum _v { ValueOne, ValueTwo, Operator, Time, Max }; };
85 int a_txMessageCounter;
86 http::Request a_httpRequest;
87 xml::Node* a_xmlRequest;
88 xml::Attribute* a_xmlAttributes [Attribute::Max];
90 /* Se invoca 4 veces por segundo */
91 bool tick () throw (RuntimeException);
94 class MyHandler : public http::Handler {
96 MyHandler () : http::Handler ("http_client::MyHandler") {;}
99 xml::DocumentMemory a_xmlRequest;
100 xml::Parser a_xmlParser;
102 void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;}
103 void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException);
105 // static bool isOk (const test::Response& response) throw ();
108 class MyCommunicator : public Communicator {
110 MyCommunicator () : Communicator (), a_avgResponseTime (0), a_rxMessageCounter (0) {;}
112 void count (const int delay) throw (RuntimeException);
115 int a_avgResponseTime;
116 int a_rxMessageCounter;
117 MyHandler a_httpHandler;
120 void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException);
122 void eventBreakConnection (const ClientSocket&) throw ();
124 // Sustituye la redefinición de los siguientes métodos
125 using comm::Communicator::eventBreakConnection;
127 void eventBreakConnection (Server* server) throw () {
128 comm::Communicator::eventBreakConnection (server);
130 void eventBreakConnection (const Service* service) throw () {
131 comm::Communicator::eventBreakConnection (service);
136 class HeavyWIMS20Client : public anna::comm::Application {
138 HeavyWIMS20Client ();
140 Server* getServer () const throw () { return a_server; }
141 const Sender* getSender () const throw () { return &a_sender; }
144 MyCommunicator a_communicator;
145 timex::Engine a_timeController;
149 void initialize () throw (RuntimeException);
150 void run () throw (RuntimeException);
155 int main (int argc, const char** argv)
157 CommandLine& commandLine (CommandLine::instantiate ());
158 HeavyWIMS20Client app;
163 commandLine.initialize (argv, argc);
164 commandLine.verify ();
166 Logger::setLevel (Logger::Information);
167 string traceFile ("client.");
168 traceFile += anna::functions::asString ((int) getpid ());
169 traceFile += ".trace";
170 Logger::initialize ("http_client", new TraceWriter (traceFile.c_str (),4096000));
174 catch (Exception& ex) {
175 cout << ex.asString () << endl;
181 HeavyWIMS20Client::HeavyWIMS20Client () :
182 Application ("http_client", "Cliente HTTP", "1.0"),
184 a_timeController (OneSecond, Resolution)
186 CommandLine& commandLine (CommandLine::instantiate ());
188 commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas.");
189 commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas.");
190 commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo");
191 commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)");
194 void HeavyWIMS20Client::initialize ()
195 throw (RuntimeException)
197 CommandLine& cl (CommandLine::instantiate ());
199 Network& network = Network::instantiate ();
201 a_server = network.createServer (cl.getValue ("a"), cl.getIntegerValue ("p"), true, &http::Transport::getFactory ());
202 a_sender.setMessageBySecond (cl.getIntegerValue ("n"));
204 if (cl.exists ("trace"))
205 Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
208 void HeavyWIMS20Client::run ()
209 throw (RuntimeException)
211 a_timeController.activate (a_sender);
213 a_communicator.accept ();
216 void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message)
217 throw (RuntimeException)
219 LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION));
221 if (clientSocket.support (http::Transport::className ()) == false)
224 a_httpHandler.apply (clientSocket, message);
227 void MyCommunicator::count (const int delay)
228 throw (RuntimeException)
230 Guard guard (this, "MyCommunicator::count");
232 a_rxMessageCounter ++;
233 a_avgResponseTime += delay;
236 void MyCommunicator::eventBreakConnection (const ClientSocket& clientSocket)
239 if (a_rxMessageCounter == 0)
243 HeavyWIMS20Client& app = static_cast <HeavyWIMS20Client&> (anna::app::functions::getApp ());
244 string msg ("Tiempo medio respuesta: ");
245 msg += anna::functions::asString (a_avgResponseTime / a_rxMessageCounter);
247 msg += anna::functions::asText (" | Rx: ", a_rxMessageCounter);
248 msg += anna::functions::asText (" | Tx: ", app.getSender ()->getTxMessageCounter ());
249 Logger::notice (msg, ANNA_FILE_LOCATION);
251 cout << msg << endl << endl;
254 comm::Communicator::eventBreakConnection (clientSocket);
257 Sender::Sender () : Clock ("Sender", Period),
261 a_txMessageCounter (0)
263 a_httpRequest.setMethod (http::Method::Type::Get);
264 a_httpRequest.setURI ("http_xmlclient.p");
267 * Crea el documento XML que usaremos para codificar la respuesta y
268 * pre-localiza los objetos sobre los que tendrá que actuar
270 a_xmlRequest = new xml::Node ("Request");
271 a_xmlAttributes [Attribute::ValueOne] = a_xmlRequest->createAttribute ("ValueOne", 0);
272 a_xmlAttributes [Attribute::ValueTwo] = a_xmlRequest->createAttribute ("ValueTwo", 0);
273 a_xmlAttributes [Attribute::Operator] = a_xmlRequest->createAttribute ("Operator", 0);
274 a_xmlAttributes [Attribute::Time] = a_xmlRequest->createAttribute ("Millisecond", 0);
278 throw (RuntimeException)
280 Server* server = static_cast <HeavyWIMS20Client&> (anna::app::functions::getApp ()).getServer ();
281 Communicator* communicator = anna::app::functions::component <Communicator> (ANNA_FILE_LOCATION);
283 if (a_errorCounter > 100) {
284 communicator->requestStop ();
285 Logger::warning ("Terminado por errores continuos en la conexion", ANNA_FILE_LOCATION);
289 for (int n = 0; n < a_messageByTick && communicator->hasRequestedStop () == false; n ++) {
290 a_xmlAttributes [Attribute::ValueOne]->setValue (rand () % 1000);
291 a_xmlAttributes [Attribute::ValueTwo]->setValue (rand () % 1000);
292 a_xmlAttributes [Attribute::Operator]->setValue ("+");
293 a_xmlAttributes [Attribute::Time]->setValue (anna::functions::millisecond ());
296 a_httpRequest.setBody (a_xmlRequest);
297 server->send (a_httpRequest);
298 a_txMessageCounter ++;
300 catch (RuntimeException& ex) {
310 void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response)
311 throw (RuntimeException)
313 if (response.getStatusCode () != 200)
316 a_xmlRequest.initialize (response.getBody ());
318 const xml::Node* root = a_xmlRequest.parse ();
320 const anna::Millisecond now = anna::functions::millisecond ();
321 const anna::Millisecond past(root->getAttribute ("Time")->getIntegerValue ());
323 const int delay = now - past;
327 string msg = a_xmlRequest.getContentAsCString ();
328 msg += anna::functions::asText (" | Delay: ", delay);
329 Logger::warning (msg, ANNA_FILE_LOCATION);
334 app::functions::component <MyCommunicator> (ANNA_FILE_LOCATION)->count (delay);