Blame view

JChatClient/src/client.cpp 4.65 KB
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
}