|
1
2
3
4
5
6
|
/** @file
* \brief Fichero de implementación de un cliente
* \author Imanol Barba Sabariego
* \date 13/06/2013
*
* En este fichero se implementa un cliente para poder usar con el servidor creado, usando la clase Socket.
|
|
7
|
* REVISADO EL 10/12/2013 PARA LA APLIACIÓN JCHAT
|
|
8
|
*/
|
|
9
|
#include "client.h"
|
|
10
11
12
|
using namespace std;
|
|
13
14
15
16
|
//! Variable de estado del programa.
bool connected;
//! Variable de estado del programa.
bool finished;
|
|
17
|
|
|
18
19
|
//! Método de liberación de los argumentos
/*! Este método se encarga de liberar la memoria asignada a los argumentos pasados a los threads que ahora han terminado. */
|
|
20
21
22
23
24
25
26
27
|
void killThread(thread_args *t_arg)
{
if(t_arg != 0)
{
delete t_arg;
t_arg = 0;
}
pthread_exit(NULL);
|
|
28
29
|
}
|
|
30
31
|
//! Método de conexión
/*! Este método conecta el cliente a una sala de chat. */
|
|
32
33
|
bool connect(Socket& s)
{
|
|
34
|
string host, nick, response;
|
|
35
|
int port;
|
|
36
|
cout << "Hostname: ";
|
|
37
|
getline(cin,host);
|
|
38
|
cout << "Port: ";
|
|
39
40
|
cin >> port;
cin.ignore();
|
|
41
|
cout << "Nickname: ";
|
|
42
|
getline(cin,nick);
|
|
43
44
45
|
host = "localhost";
port = 3001;
|
|
46
47
|
try
{
|
|
48
|
s.Create();
|
|
49
50
51
|
s.Connect(host,port);
cout << "Connected" << endl;
connected = true;
|
|
52
|
s << nick;
|
|
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
s >> response;
while(response == "CHATNICKINVALID")
{
cout << "Spaces not allowed in nicknames, please enter another nickname: ";
getline(cin,nick);
s << nick;
s >> response;
}
while(response == "CHATNICKEXIST")
{
cout << "Nickname in use, please enter another nickname: ";
getline(cin,nick);
s << nick;
s >> response;
}
while(response == "CHATFULL")
{
cout << "Chatroom is full, please wait..." << endl;
|
|
71
72
|
s.Close();
return false;
|
|
73
74
75
76
|
}
if(response != "CHATOK")
{
cout << "Error: " << response << endl;
|
|
77
|
s.Close();
|
|
78
79
|
return false;
}
|
|
80
81
82
83
|
}
catch(SocketException& e)
{
cout << e.description() << endl;
|
|
84
|
exit(-1);
|
|
85
|
}
|
|
86
|
return true;
|
|
87
88
|
}
|
|
89
90
|
//! Thread de envío de mensajes
/*! Este método es ejecutado por un thread con el objetivo de enviar los mensajes y comandos que el usuario introduce por teclado. */
|
|
91
|
void* sendThread(void* args)
|
|
92
|
{
|
|
93
94
|
string send;
struct thread_args *t_arg = (struct thread_args*)args;
|
|
95
|
while(connected)
|
|
96
|
{
|
|
97
98
99
100
|
cout << "> ";
getline(cin,send);
if(cin.eof())
{
|
|
101
|
send = "/exit";
|
|
102
103
104
105
106
107
108
109
110
111
112
113
114
|
}
try
{
*(t_arg->s) << send;
if(send == "/disconnect" || send == "/exit")
{
break;
}
}
catch(SocketException& e)
{
cout << e.description() << endl;
}
|
|
115
|
}
|
|
116
117
118
|
killThread(t_arg);
}
|
|
119
120
|
//! Thread de recepción de mensajes
/*! Este método es ejecutado por un thread con el objetivo de recibir los mensajes por el socket, gestionarlos e imprimirlos por pantalla o tomar las medidas necesarias .*/
|
|
121
122
123
124
125
|
void* recvThread(void* args)
{
string recv;
struct thread_args *t_arg = (struct thread_args*)args;
while(true)
|
|
126
|
{
|
|
127
128
129
130
131
132
133
134
|
try
{
*(t_arg->s) >> recv;
}
catch(SocketException &e)
{
connected = false;
cout << e.description() << endl;
|
|
135
136
|
cout << "Connection lost. Press Enter to retry connection to chatroom. Press CTRL+C to exit." << endl;
pthread_cond_signal(t_arg->condition);
|
|
137
138
|
break;
}
|
|
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
if(recv == "DISC_OK")
{
cout << "Disconnecting" << endl;
connected = false;
pthread_cond_signal(t_arg->condition);
break;
}
else if(recv == "EXIT_OK")
{
cout << "Exiting" << endl;
connected = false;
finished = true;
pthread_cond_signal(t_arg->condition);
break;
}
else
{
cout << recv << endl;
}
|
|
158
|
}
|
|
159
|
killThread(t_arg);
|
|
160
161
162
163
164
165
|
}
//! Método principal del cliente
/*! Este método inicializa el Socket, establece la conexión y realiza las acciones que se le hayan programado para comunicarse con el servidor.*/
int main()
{
|
|
166
|
//signal(SIGPIPE, exitClient); UNUSED
|
|
167
168
|
Socket s;
connected = finished = false;
|
|
169
170
171
172
173
|
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,0);
pthread_cond_t condition;
pthread_cond_init(&condition,0);
pthread_t recv, send;
|
|
174
175
176
|
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
|
177
|
int retries = 3;
|
|
178
|
while (!finished)
|
|
179
|
{
|
|
180
|
while(!connect(s))
|
|
181
|
{
|
|
182
183
184
185
186
187
|
if((--retries) <= 0)
{
cout << "Exiting" << endl;
exit(-1);
}
cout << "Couldn't connect to chatroom, retrying..." << endl;
|
|
188
|
}
|
|
189
|
pthread_mutex_lock(&mutex);
|
|
190
191
|
thread_args *sArgs = new thread_args;
thread_args *rArgs = new thread_args;
|
|
192
193
194
195
196
197
198
199
|
sArgs->mutex = &mutex;
sArgs->condition = &condition;
sArgs->s = &s;
rArgs->mutex = &mutex;
rArgs->condition = &condition;
rArgs->s = &s;
|
|
200
201
|
pthread_create(&send,&attr,sendThread,(void *)sArgs);
pthread_create(&recv,&attr,recvThread,(void *)rArgs);
|
|
202
|
|
|
203
204
|
while(connected)
{
|
|
205
|
pthread_cond_wait(&condition,&mutex);
|
|
206
|
}
|
|
207
|
pthread_mutex_unlock(&mutex);
|
|
208
209
210
|
pthread_join(recv,NULL);
pthread_join(send,NULL);
s.Close();
|
|
211
|
}
|
|
212
213
|
pthread_cond_destroy(&condition);
pthread_mutex_destroy(&mutex);
|
|
214
|
}
|