First commit
[anna.git] / example / comm / client / main.cpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
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
16 // distribution.
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.
20 //
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.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 /**
38    Realiza peticiones automaticas sobre el servidor de operaciones aritmeticas.
39
40    La cadencia de envio de mensajes se establece mediante un temporizador.
41    Los operadores se calculan de forma aleatoria.
42
43    El servidor de este cliente: server
44 */
45
46 #include <iostream>
47
48 #include <string.h>
49 #include <unistd.h>
50
51 #include <anna/core/core.hpp>
52 #include <anna/app/functions.hpp>
53 #include <anna/comm/comm.hpp>
54
55 #include <anna/timex/Engine.hpp>
56 #include <anna/timex/Clock.hpp>
57
58 #include <anna/test/Response.hpp>
59 #include <anna/test/Request.hpp>
60
61 class Sender : public timex::Clock {
62 public:
63    Sender () : Clock ("Sender", (Millisecond)1000), 
64       a_messageBySecond (0), 
65       a_nquarter (0), 
66       a_requests ("Request"), 
67       a_errorCounter (0),
68       a_txMessageCounter (0)
69    {;}
70
71    void setMessageBySecond (const int messageBySecond) throw () { a_messageBySecond = messageBySecond; }
72
73    int getTxMessageCounter () const throw () { return a_txMessageCounter; }
74
75 private:
76    int a_messageBySecond;
77    int a_nquarter;
78    int a_errorCounter;
79    int a_txMessageCounter;
80    ThreadData <test::Request> a_requests;
81
82    bool tick () throw (RuntimeException);
83 };
84
85 class MyCommunicator : public Communicator {
86 public:
87    MyCommunicator () : Communicator (), a_avgResponseTime (0), a_rxMessageCounter (0), a_responses ("Response")  {;}
88
89 private:
90    ThreadData <test::Response> a_responses;
91    int a_avgResponseTime;
92    int a_rxMessageCounter;
93
94    void eventReceiveMessage (ClientSocket &, const Message&)
95       throw (RuntimeException);
96
97    void eventBreakConnection (const ClientSocket&) throw ();
98
99    void eventBreakConnection (Server* server) throw () {
100       comm::Communicator::eventBreakConnection (server);
101    }
102    void eventBreakConnection (const Service* service) throw () { 
103       comm::Communicator::eventBreakConnection (service);
104    }
105    
106    static bool isOk (const test::Response& response) throw ();
107 };
108
109 class HeavyClient : public anna::comm::Application {
110 public:
111    HeavyClient ();
112
113    Server* getServer () const throw () { return a_server; }
114    const Sender* getSender () const throw () { return &a_sender; }
115
116 private:
117    MyCommunicator a_communicator;
118    timex::Engine a_timeController;
119    Sender a_sender;
120    Server* a_server;
121
122    void initialize () throw (RuntimeException);
123    void run () throw (RuntimeException);
124 };
125
126 using namespace std;
127
128 int main (int argc, const char** argv)
129 {
130    CommandLine& commandLine (CommandLine::instantiate ());
131    HeavyClient app;
132
133    srand (time (NULL));
134
135    try {
136       commandLine.initialize (argv, argc);
137       commandLine.verify ();
138
139       Logger::setLevel (Logger::Information);
140       string traceFile ("client.");
141       traceFile += anna::functions::asString ((int) getpid ());
142       traceFile += ".trace";
143       Logger::initialize ("arithmeticClient", new TraceWriter (traceFile.c_str (),4096000));
144
145       app.start ();
146    }
147    catch (Exception& ex) {
148       cout << ex.asString () << endl;
149    }
150
151    return 0;
152 }
153
154 HeavyClient::HeavyClient () :
155    Application ("arithmeticClient", "Cliente de operaciones aritm�icas", "1.0"),
156    a_communicator (),
157    a_timeController ((Millisecond)1000, (Millisecond)250)
158 {
159    CommandLine& commandLine (CommandLine::instantiate ());
160
161    commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas.");
162    commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas.");
163    commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo");
164    commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)");
165 }
166
167 void HeavyClient::initialize ()
168    throw (RuntimeException)
169 {
170    CommandLine& cl (CommandLine::instantiate ());
171
172    Network& network = Network::instantiate ();
173
174    a_server = network.createServer (cl.getValue ("a"), cl.getIntegerValue ("p"), true);
175    a_sender.setMessageBySecond (cl.getIntegerValue ("n"));
176
177    if (cl.exists ("trace"))
178       Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
179 }
180
181 void HeavyClient::run ()
182    throw (RuntimeException)
183 {
184    a_timeController.activate (a_sender);
185
186    a_communicator.accept ();
187 }
188
189 void MyCommunicator::eventReceiveMessage (ClientSocket&, const Message& message)
190    throw (RuntimeException)
191 {
192    test::Response& response = a_responses.get ();
193    response.decode (message.getBody ());
194
195    const anna::Millisecond now = anna::functions::millisecond ();
196    const int delay =  now - (Millisecond) response.initTime;
197
198    if (delay > 0 && isOk (response) == true) {
199       a_rxMessageCounter ++;
200       a_avgResponseTime += delay;
201
202       LOGINFORMATION (
203          string msg = anna::functions::asString (
204             "%d %c %d = %d", response.x, response.op, response.y, response.result
205          );
206          msg += anna::functions::asText (" | Delay: ", delay);
207          Logger::information (msg, ANNA_FILE_LOCATION);
208       );
209    }
210    else {
211       LOGWARNING (
212          string msg = anna::functions::asString (
213             "Flip: %d %c %d = %d", response.x, response.op, response.y, response.result
214          );
215          msg += anna::functions::asText (" | Message: ", message.getBody ());
216          msg += anna::functions::asText (" | Delay: ", delay);
217          Logger::warning (msg, ANNA_FILE_LOCATION);
218       );
219    }
220 }
221
222 void MyCommunicator::eventBreakConnection (const ClientSocket& clientSocket)
223    throw ()
224 {
225    if (a_rxMessageCounter == 0)
226       return;
227
228    LOGNOTICE (
229       HeavyClient& app = static_cast <HeavyClient&> (anna::app::functions::getApp ());   
230       string msg ("Tiempo medio respuesta: ");
231       msg += anna::functions::asString (a_avgResponseTime / a_rxMessageCounter);
232       msg += " ms";
233       msg += anna::functions::asText (" | Rx: ", a_rxMessageCounter);
234       msg += anna::functions::asText (" | Tx: ", app.getSender ()->getTxMessageCounter ());
235       Logger::notice (msg, ANNA_FILE_LOCATION);
236
237       cout << msg << endl << endl;
238    );
239    requestStop ();
240    comm::Communicator::eventBreakConnection (clientSocket);
241 }
242
243 bool MyCommunicator::isOk (const test::Response& response) 
244    throw ()
245 {
246    if (response.op != '+' && response.op != '-' && response.op != '*' && response.op != '/') 
247       return false;
248       
249    int result = 0;
250    
251    switch (response.op) {
252       case '+':
253          result = response.x + response.y;
254          break;
255       case '-':
256          result = response.x - response.y;
257          break;
258       case '*':
259          result = response.x * response.y;
260          break;
261       case '/':
262          result = (response.y != 0) ? (response.x / response.y): 0;
263          break;
264    }
265     
266    return result == response.result;   
267 }
268
269 bool Sender::tick ()
270    throw (RuntimeException)
271 {
272    Server* server = static_cast <HeavyClient&> (anna::app::functions::getApp ()).getServer ();
273    Communicator* communicator = anna::app::functions::component <Communicator> (ANNA_FILE_LOCATION);
274
275    if (a_errorCounter > 10) {
276       Logger::warning ("Terminado por errores continuos en la conexion", ANNA_FILE_LOCATION);
277       try {
278          communicator->requestStop ();
279       }
280       catch (RuntimeException& ex) {
281          ex.trace ();
282       }
283       return false;
284    }
285
286    test::Request& request = a_requests.get ();
287
288    for (int n = 0; n < a_messageBySecond && communicator->hasRequestedStop () == false; n ++) {
289       request.op = '+';
290       request.x = rand () % 1000;
291       request.y = rand () % 1000;
292       request.initTime = anna::functions::millisecond ();
293
294       try {
295          server->send (request);
296          a_txMessageCounter ++;
297       }
298       catch (RuntimeException& ex) {
299          string msg (ex.getText ());
300          msg += anna::functions::asText (" | ErrorCounter: ", ++ a_errorCounter);
301          Logger::warning (msg, ANNA_FILE_LOCATION);
302          break;
303       }
304    }
305
306    return true;
307 }
308