/** @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. * REVISADO EL 10/12/2013 PARA LA APLIACIÓN JCHAT */ #include "client.h" using namespace std; //! Variable de estado del programa. bool connected; //! Variable de estado del programa. bool finished; //! 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. */ void killThread(thread_args *t_arg) { if(t_arg != 0) { delete t_arg; t_arg = 0; } pthread_exit(NULL); } //! Método de conexión /*! Este método conecta el cliente a una sala de chat. */ bool connect(Socket& s) { string host, nick, response; int port; cout << "Hostname: "; getline(cin,host); cout << "Port: "; cin >> port; cin.ignore(); cout << "Nickname: "; getline(cin,nick); host = "localhost"; port = 3001; try { s.Create(); s.Connect(host,port); cout << "Connected" << endl; connected = true; s << nick; 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; s.Close(); return false; } if(response != "CHATOK") { cout << "Error: " << response << endl; return false; } } catch(SocketException& e) { cout << e.description() << endl; exit(-1); } return true; } //! 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. */ void* sendThread(void* args) { string send; struct thread_args *t_arg = (struct thread_args*)args; while(connected) { cout << "> "; getline(cin,send); if(cin.eof()) { send = "/exit"; } try { *(t_arg->s) << send; if(send == "/disconnect" || send == "/exit") { break; } } catch(SocketException& e) { cout << e.description() << endl; } } killThread(t_arg); } //! 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 .*/ void* recvThread(void* args) { string recv; struct thread_args *t_arg = (struct thread_args*)args; while(true) { try { *(t_arg->s) >> recv; } catch(SocketException &e) { connected = false; cout << e.description() << endl; cout << "Connection lost. Press Enter to retry connection to chatroom. Press CTRL+C to exit." << endl; pthread_cond_signal(t_arg->condition); break; } 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; } } killThread(t_arg); } //! 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() { //signal(SIGPIPE, exitClient); UNUSED Socket s; connected = finished = false; pthread_mutex_t mutex; pthread_mutex_init(&mutex,0); pthread_cond_t condition; pthread_cond_init(&condition,0); pthread_t recv, send; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); int retries = 3; while (!finished) { while(!connect(s)) { if((--retries) <= 0) { cout << "Exiting" << endl; exit(-1); } cout << "Couldn't connect to chatroom, retrying..." << endl; } pthread_mutex_lock(&mutex); thread_args *sArgs = new thread_args; thread_args *rArgs = new thread_args; sArgs->mutex = &mutex; sArgs->condition = &condition; sArgs->s = &s; rArgs->mutex = &mutex; rArgs->condition = &condition; rArgs->s = &s; pthread_create(&send,&attr,sendThread,(void *)sArgs); pthread_create(&recv,&attr,recvThread,(void *)rArgs); while(connected) { pthread_cond_wait(&condition,&mutex); } pthread_mutex_unlock(&mutex); pthread_join(recv,NULL); pthread_join(send,NULL); s.Close(); } pthread_cond_destroy(&condition); pthread_mutex_destroy(&mutex); }