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