Commit 493ea8e792d6cb2328647617b2621f6681eb2241

Authored by Imanol-Mikel Barba Sabariego
1 parent 791d4e1f

git-svn-id: svn://imanolbarba.net/PAD@25 c2ee353e-ed0d-4329-bf56-03aec153487f

JChatClient/bin/client
No preview for this file type
JChatClient/src/client.cpp
@@ -5,13 +5,7 @@ @@ -5,13 +5,7 @@
5 * 5 *
6 * En este fichero se implementa un cliente para poder usar con el servidor creado, usando la clase Socket. 6 * En este fichero se implementa un cliente para poder usar con el servidor creado, usando la clase Socket.
7 */ 7 */
8 -#include "Socket.h"  
9 -#include <iostream>  
10 -#include "SocketException.h"  
11 -#include <sstream>  
12 -#include <signal.h>  
13 -#include <cstdlib>  
14 -#include <sys/time.h> 8 +#include "client.h"
15 9
16 using namespace std; 10 using namespace std;
17 11
@@ -22,24 +16,50 @@ bool connected, finished; @@ -22,24 +16,50 @@ bool connected, finished;
22 el signal SIGPIPE. */ 16 el signal SIGPIPE. */
23 void exitClient(int signal/*!<Parámetro que captura el signal recibido*/) 17 void exitClient(int signal/*!<Parámetro que captura el signal recibido*/)
24 { 18 {
25 - cout << "Server connection terminated unexpectedly" << endl << "Exiting" << endl;  
26 - exit(-1); 19 + if(signal == SIGPIPE)
  20 + {
  21 + cout << "Server connection terminated unexpectedly" << endl << "Exiting" << endl;
  22 + exit(-1);
  23 + }
  24 +}
  25 +
  26 +void killThread(thread_args *t_arg)
  27 +{
  28 + (t_arg->s)->Close();
  29 + pthread_mutex_lock(t_arg->mutex);
  30 + if(t_arg->s != 0)
  31 + {
  32 + delete t_arg->s;
  33 + t_arg->s = 0;
  34 + }
  35 + if(t_arg != 0)
  36 + {
  37 + delete t_arg;
  38 + t_arg = 0;
  39 + }
  40 + pthread_exit(NULL);
27 } 41 }
28 42
29 bool connect(Socket& s) 43 bool connect(Socket& s)
30 { 44 {
31 - string host; 45 + string host, nick;
32 int port; 46 int port;
33 - cout << "Hostname: "; 47 + /*cout << "Hostname: ";
34 cin >> host; 48 cin >> host;
35 cout << "Port: "; 49 cout << "Port: ";
36 - cin >> port; 50 + cin >> port;*/
  51 + cout << "Nickname: ";
  52 + cin >> nick;
37 cin.ignore(); 53 cin.ignore();
  54 + host = "localhost";
  55 + port = 3001;
  56 +
38 try 57 try
39 { 58 {
40 s.Connect(host,port); 59 s.Connect(host,port);
41 cout << "Connected" << endl; 60 cout << "Connected" << endl;
42 connected = true; 61 connected = true;
  62 + s << nick;
43 } 63 }
44 catch(SocketException& e) 64 catch(SocketException& e)
45 { 65 {
@@ -47,32 +67,68 @@ bool connect(Socket&amp; s) @@ -47,32 +67,68 @@ bool connect(Socket&amp; s)
47 } 67 }
48 } 68 }
49 69
50 -void speedTest(Socket& s) 70 +void* sendThread(void* args)
51 { 71 {
52 - string data = "", answer;  
53 - double size;  
54 - double start, duration;  
55 - cout << "Size in MB: ";  
56 - cin >> size;  
57 - cin.ignore();  
58 - for(long int i = 0; i < size*1e6; i++ ) 72 + string send;
  73 + struct thread_args *t_arg = (struct thread_args*)args;
  74 + while(true)
59 { 75 {
60 - data += (char)( 65 + i % 26); 76 + cout << "> ";
  77 + getline(cin,send);
  78 + if(cin.eof())
  79 + {
  80 + send = "/disconnect";
  81 + }
  82 + try
  83 + {
  84 + *(t_arg->s) << send;
  85 + if(send == "/disconnect" || send == "/exit")
  86 + {
  87 + break;
  88 + }
  89 + }
  90 + catch(SocketException& e)
  91 + {
  92 + cout << e.description() << endl;
  93 + cout << "Exiting" << endl;
  94 + (t_arg->s)->Close();
  95 + exit(-1);
  96 + }
61 } 97 }
62 - cout << "Data generated, commencing transfer" << endl;  
63 - struct timeval st, ed;  
64 - gettimeofday(&st, NULL);  
65 - s << data;  
66 - cout << "Data sent" << endl;  
67 - s >> answer;  
68 - gettimeofday(&ed, NULL);  
69 - start = (st.tv_sec) + (st.tv_usec) / 1e6;  
70 - duration = ((ed.tv_sec) + (ed.tv_usec) / 1e6) - start;  
71 - if(answer == "ACK") 98 + killThread(t_arg);
  99 +}
  100 +
  101 +void* recvThread(void* args)
  102 +{
  103 + string recv;
  104 + struct thread_args *t_arg = (struct thread_args*)args;
  105 + while(true)
72 { 106 {
73 - cout << "Transferred " << size << " MB in " << duration << " seconds" << endl;  
74 - cout << "Data rate: " << size/duration << " MB/s" << endl; 107 + *(t_arg->s) >> recv;
  108 + if(recv == "DISC_OK")
  109 + {
  110 + cout << "Disconnecting" << endl;
  111 + (t_arg->s)->Close();
  112 + connected = false;
  113 + pthread_cond_signal(t_arg->condition);
  114 + break;
  115 + }
  116 + else if(recv == "EXIT_OK")
  117 + {
  118 + cout << "Exiting" << endl;
  119 + (t_arg->s)->Close();
  120 + connected = false;
  121 + finished = true;
  122 + pthread_cond_signal(t_arg->condition);
  123 + break;
  124 + }
  125 + else
  126 + {
  127 + *(t_arg->s) >> recv;
  128 + cout << recv << endl;
  129 + }
75 } 130 }
  131 + killThread(t_arg);
76 } 132 }
77 133
78 //! Método principal del cliente 134 //! Método principal del cliente
@@ -80,71 +136,43 @@ void speedTest(Socket&amp; s) @@ -80,71 +136,43 @@ void speedTest(Socket&amp; s)
80 int main() 136 int main()
81 { 137 {
82 signal(SIGPIPE, exitClient); 138 signal(SIGPIPE, exitClient);
83 - signal(SIGINT, exitClient);  
84 Socket s; 139 Socket s;
85 connected = finished = false; 140 connected = finished = false;
86 - string send, recv; 141 + pthread_mutex_t mutex;
  142 + pthread_mutex_init(&mutex,0);
  143 + pthread_cond_t condition;
  144 + pthread_cond_init(&condition,0);
  145 + thread_args *sArgs = new thread_args;
  146 + thread_args *rArgs = new thread_args;
  147 + pthread_t recv, send;
87 s.Create(); 148 s.Create();
88 - while (!exit) 149 + while (!finished)
89 { 150 {
90 connect(s); 151 connect(s);
  152 + pthread_mutex_lock(&mutex);
  153 + sArgs->mutex = &mutex;
  154 + sArgs->condition = &condition;
  155 + sArgs->s = &s;
  156 +
  157 + rArgs->mutex = &mutex;
  158 + rArgs->condition = &condition;
  159 + rArgs->s = &s;
  160 +
  161 + pthread_create(&send,NULL,sendThread,(void *)sArgs);
  162 + pthread_create(&recv,NULL,recvThread,(void *)rArgs);
  163 +
91 while(connected) 164 while(connected)
92 { 165 {
93 - cout << "> ";  
94 - getline(cin,send);  
95 - if(cin.eof())  
96 - {  
97 - send = "/disconnect";  
98 - }  
99 - try  
100 - {  
101 - s << send;  
102 - if(send == "/disconnect")  
103 - {  
104 - s >> recv;  
105 - if(recv == "OK")  
106 - {  
107 - cout << "Disconnecting" << endl;  
108 - s.Close();  
109 - connected = false;  
110 - }  
111 - }  
112 - else if(send == "/exit")  
113 - {  
114 - s >> recv;  
115 - if(recv == "OK")  
116 - {  
117 - cout << "Exiting" << endl;  
118 - s.Close();  
119 - connected = false;  
120 - finished = true;  
121 - }  
122 - }  
123 - else if(send == "/test")  
124 - {  
125 - speedTest(s);  
126 - }  
127 - else  
128 - {  
129 - s >> recv;  
130 - cout << "Received: " << recv << endl;  
131 - }  
132 - }  
133 - catch(SocketException& e)  
134 - {  
135 - cout << e.description() << endl;  
136 - cout << "Exiting" << endl;  
137 - s.Close();  
138 - return -1;  
139 - } 166 + pthread_cond_wait(&condition,&mutex);
140 } 167 }
  168 + pthread_mutex_unlock(&mutex);
141 } 169 }
  170 + pthread_cond_destroy(&condition);
  171 + pthread_mutex_destroy(&mutex);
142 } 172 }
143 173
144 -/* TO-DO 174 +/* TODO
145 * 175 *
146 - * spawn 2 IO threads  
147 - * connect/disconnect commands  
148 * list nicks 176 * list nicks
149 * unicast message 177 * unicast message
150 */ 178 */
151 \ No newline at end of file 179 \ No newline at end of file
JChatClient/src/include/client.h 0 → 100644
  1 +#ifndef CLIENT_H_
  2 +#define CLIENT_H_
  3 +
  4 +#include "Socket.h"
  5 +#include <iostream>
  6 +#include "SocketException.h"
  7 +#include <sstream>
  8 +#include <signal.h>
  9 +#include <cstdlib>
  10 +#include <sys/time.h>
  11 +
  12 +//!Argumentos de los threads
  13 +/**
  14 +\brief Este struct define los argumentos que recibe un thread abierto por la aplicación servidor al recibir una conexión entrante
  15 +\author Imanol Barba Sabariego
  16 +\date 11/06/2013 */
  17 +struct thread_args
  18 +{
  19 + //! Variable de control de la exclusión mútua entre threads
  20 + /** Esta variable se usa para bloquear otros threads en operaciones de exclusion mútua donde se modifican variables compartidas */
  21 + pthread_mutex_t *mutex;
  22 + //! Variable de notificación a otros threads
  23 + /*! \brief Esta variable se usa para notificar a otros threads cuando deben realizar otras acciones.
  24 +
  25 + *Actualmente se usa para notificar al thread principal cuando el thread que lo invoca ha terminado, en caso de que el principal haya
  26 + quedado bloqueado y no admita más conexiones.* */
  27 + pthread_cond_t *condition;
  28 + //! Puntero al socket
  29 + /*! \brief Esta variable representa el puntero al socket que proviene de la conexión entrante recibida por el servidor. Con este, el thread
  30 + puede recibir y enviar los datos. */
  31 + Socket *s;
  32 +};
  33 +
  34 +
  35 +
  36 +#endif /* CLIENT_H_ */
0 \ No newline at end of file 37 \ No newline at end of file
JChatClient/src/include/server.h deleted
1 -/** @file  
2 -* \brief Header de la clase Server  
3 -* \author Imanol Barba Sabariego  
4 -* \date 11/06/2013  
5 -*  
6 -* En este fichero se define la clase Server y algunos métodos globales usados por ésta para la gestión de threads y otros aspectos.  
7 -*/  
8 -  
9 -#ifndef SERVER_H_  
10 -#define SERVER_H_  
11 -  
12 -#include "Socket.h"  
13 -#include "SocketException.h"  
14 -#include <iostream>  
15 -#include <sstream>  
16 -#include <signal.h>  
17 -#include <fstream>  
18 -#include <list>  
19 -#include <fstream>  
20 -  
21 -//! Numero de conexiones permitidas activas (en espera o activas)  
22 -/*! Esta constante controla cuantas conexiones puede haber en espera o cuantas puede haber establecias en cualquier momento: habrá N activas  
23 -y N en espera como mucho, no N en espera o activas. */  
24 -#define N 5  
25 -//! Ruta al fichero de configuración  
26 -/*! Ruta relativa o absoluta al fichero de configuración, de no existir o ser inválido el programa no funcionará. */  
27 -#define CONFFILE "socket.conf"  
28 -//! Nombre del socket del módulo de control  
29 -/*! Nombre y ruta del socket UNIX del módulo de control */  
30 -  
31 -using namespace std;  
32 -  
33 -//! Clase de aplicación servidor  
34 -/**  
35 -Esta clase define un objeto con los métodos y atributos necesarios para lanzar una aplicación servidor y atender las conexiones. Para realizar  
36 -la comunicación con el cliente, usa un objeto de la clase Socket  
37 -*/  
38 -class Server  
39 -{  
40 - private:  
41 - //! Contador de threads  
42 - /*! Esta variable se encarga de mantener la cuenta de threads activos, por tanto, el número de conexiones que estan siendo antendidas  
43 - simultáneamente. */  
44 - int nWorkers;  
45 - //! Variable de apagado  
46 - /*! Esta variable controla el apagado del servidor, al ponerla a true, la siguiente iteración del bucle que atiende las conexiones  
47 - no se producirá y el programa terminará. */  
48 - bool shutdownServer;  
49 - //! Contador de ID de thread  
50 - /*! Esta variable contiene el ID del próximo thread que se creará, por tanto, indica el número de conexiones que han sido atendidas desde  
51 - el inicio del servidor */  
52 - int workerID;  
53 - //! Pila de threads terminados  
54 - /*! Esta variable contiene una lista de threads que han finalizado su ejecución. A cada iteración del bucle que atiende conexiones,  
55 - se libera toda la memoria de los threads que hay almacenados aquí. */  
56 - list<pthread_t*> stoppedThreads;  
57 - //! Pila de threads empezados  
58 - /*! \brief Esta variable contiene una lista de threads que han empezado su ejecución. Si el programa finalizara prematuramente, se liberarían los punteros  
59 - de los threads almacenados en esta pila.  
60 -  
61 - __NOTA: No se liberará la memoria asignada a los argumentos de los threads, dando lugar a memory leaks; sin embargo, esto se produciria al finalizar  
62 - el programa, por tanto no es relevante.__ */  
63 - list<pthread_t*> startedThreads;  
64 - //! Socket de comunicación  
65 - /*! Esta variable contiene el objeto de la clase Socket que la aplicación servidor usa para poder atender las peticiones. Su función  
66 - es quedarse escuchando el el puerto e IP introducidas en el fichero de configuración y crear un objeto de la clase Socket para cada  
67 - petición de cada cliente nuevo, siendo este último objeto creado el que se usa para la comuncación. */  
68 - Socket ss;  
69 -  
70 - public:  
71 - //! Constructor de la clase Server  
72 - /*! Incializa los argumentos inciales del servidor */  
73 - Server() : nWorkers(0), workerID(0), shutdownServer(false) {}  
74 - //! Getter del número de threads activos  
75 - /*! Devuelve el número de threads activos en ese instante, por tanto, del número de conexiones que están siendo atendidas. */  
76 - int getNWorkers();  
77 - //! Setter del número de threads activos  
78 - /*! Establece el número de threads activos, para poder cambiarlo cuando alguno de los threads activos finaliza */  
79 - void setNWorkers(int n /*!<Nuevo número de threads activos*/);  
80 - //! Getter de la pila de threads activos  
81 - /*! Devuelve un contenedor con la lista de threads que estan activos, para terminarlos en caso de que el programa finalice prematuramente */  
82 - list<pthread_t*>* getStartedThreads();  
83 - //! Getter de la pila de threads terminados  
84 - /*! Devuelve un contenedor con la lista de threads que han terminado, para poder liberar la memoria que se le ha asignado */  
85 - list<pthread_t*>* getStoppedThreads();  
86 - //! Método de inicialización del servidor  
87 - /*! Incializa el servidor en el puerto e IP especificados para empezar a recibir conexiones entrantes */  
88 - void startServer(string i /*!<IP donde se aceptan las conexiones */, int p/*!<Puerto donde se aceptan las conexiones*/);  
89 - //! Método para liberar memória de threads  
90 - /*! Este método se llama para que libere la memoria de todos los threads que se le proporcionan por argumento */  
91 - void freeRAM(list<pthread_t*> *threadList/*!<Contenedor con los threads a liberar */);  
92 - //! Método para terminar el servidor  
93 - /*! Este método inicia la secuencia de finalización del servidor */  
94 - void requestExit();  
95 -};  
96 -  
97 -//!Argumentos de los threads  
98 -/**  
99 -\brief Este struct define los argumentos que recibe un thread abierto por la aplicación servidor al recibir una conexión entrante  
100 -\author Imanol Barba Sabariego  
101 -\date 11/06/2013 */  
102 -struct thread_args  
103 -{  
104 - //! Variable de control de la exclusión mútua entre threads  
105 - /** Esta variable se usa para bloquear otros threads en operaciones de exclusion mútua donde se modifican variables compartidas */  
106 - pthread_mutex_t *mutex;  
107 - //! Variable de notificación a otros threads  
108 - /*! \brief Esta variable se usa para notificar a otros threads cuando deben realizar otras acciones.  
109 -  
110 - *Actualmente se usa para notificar al thread principal cuando el thread que lo invoca ha terminado, en caso de que el principal haya  
111 - quedado bloqueado y no admita más conexiones.* */  
112 - pthread_cond_t *condition;  
113 - //! Puntero al thread  
114 - /*! \brief Esta variable representa el puntero del propio thread. Al finalizar, este enviará su puntero a la lista de threads terminados,  
115 - donde la memoria asignada al thread se destruirá. */  
116 - pthread_t *thread;  
117 - //! Puntero al socket  
118 - /*! \brief Esta variable representa el puntero al socket que proviene de la conexión entrante recibida por el servidor. Con este, el thread  
119 - puede recibir y enviar los datos. */  
120 - Socket *s;  
121 - //! Puntero al servidor  
122 - /*! \brief Esta variable representa el puntero al servidor de la aplicación. Con este puntero, los threads se mueven a la pila de threads  
123 - terminados una vez terminan la ejecución para que el thread principal (el propio servidor), vaya liberando la memoria asignada. */  
124 - Server *serv;  
125 - //! ID del thread  
126 - /*! \brief Identifica al thread con un ID único */  
127 - int id;  
128 -};  
129 -  
130 -//! Método de finalización de Threads  
131 -/*! \brief Éste método se ejecuta para liberar la memoria de los argumentos del thread y mandarlo a la pila de threads terminados. */  
132 -void killThread(thread_args *t_arg /*!<Puntero al struct que contiene los argumentos del thread */);  
133 -//! Método gestión de conexiones  
134 -/*! \brief Éste método es el que los threads ejecutan al crearse, aquí es donde se define el comportamiento del servidor, ya que cada conexión  
135 -se gestionará como aquí se detalla.  
136 -  
137 -_Por defecto, el comportamiento que lleva programado es el de un servidor "echo", esperará que el cliente le envíe un mensaje y responderá con el  
138 -mismo mensaje._ */  
139 -void *WorkerThread(void* args /*!< Puntero al struct de los argumentos del thread casteado a tipo void**/);  
140 -//! Método auxiliar de procesado de texto  
141 -/*! \brief Éste método usa para procesar las entradas de texto del fichero de configuración para adaptarlas a un formato adecuado.  
142 -  
143 -_De momento se limita a eliminar whitespace (tabulaciones, saltos de línea y espacios)._ */  
144 -void processText(string *str/*!<Línea de texto a procesar*/);  
145 -//! Método de lectura de configuración  
146 -/*! \brief Éste método lee el fichero de configuración espeficado para obtener parámetros de configuración para el funcionamiento del servidor. */  
147 -bool readConf(string *ip/*!Puntero donde se almacena la IP leída*/, int *port/*!<Puntero donde se almacena el puerto leído*/);  
148 -  
149 -#endif /* SERVER_H_ */  
JChatServer/bin/pad/prac2/Connection.class
No preview for this file type
JChatServer/bin/pad/prac2/JChat.class
No preview for this file type
JChatServer/bin/pad/prac2/MyServerSocket.class
No preview for this file type
JChatServer/bin/pad/prac2/MySocket.class
No preview for this file type
JChatServer/bin/pad/prac2/Server.class
No preview for this file type
JChatServer/bin/pad/prac2/Worker.class deleted
No preview for this file type
JChatServer/src/pad/prac2/Connection.java
1 package pad.prac2; 1 package pad.prac2;
2 2
3 -public class Connection 3 +public class Connection extends Thread
4 { 4 {
  5 + private MySocket socket;
  6 + private Server serv;
  7 + private boolean sleep, kill;
  8 +
  9 + public Connection(Server s)
  10 + {
  11 + serv = s;
  12 + kill = false;
  13 + sleep = true;
  14 + }
  15 +
  16 + public void sendMessage(String message)
  17 + {
  18 + socket.sendMsg(message);
  19 + }
  20 +
  21 + public void awake()
  22 + {
  23 + synchronized(this)
  24 + {
  25 + sleep = false;
  26 + this.notify();
  27 + }
  28 + }
  29 +
  30 + public void finish()
  31 + {
  32 + kill = true;
  33 + sleep = false;
  34 + socket.close();
  35 + this.notify();
  36 + }
  37 +
  38 + public void setSock(MySocket s)
  39 + {
  40 + socket = s;
  41 + }
  42 +
  43 + public void run()
  44 + {
  45 + while(!kill)
  46 + {
  47 + while(sleep)
  48 + {
  49 + try
  50 + {
  51 + synchronized(this)
  52 + {
  53 + wait();
  54 + }
  55 + }
  56 + catch (InterruptedException e)
  57 + {
  58 + e.printStackTrace();
  59 + }
  60 + }
  61 + String str = socket.recvMsg();
  62 + serv.addToChatroom(this, str);
  63 + if(!kill)
  64 + {
  65 + while(true)
  66 + {
  67 + str = socket.recvMsg();
  68 + if(str != null)
  69 + {
  70 + if(str == "/disconnect")
  71 + {
  72 + socket.sendMsg("DISC_OK");
  73 + kill = true;
  74 + System.out.println(serv.getNickname(this) + " disconnected");
  75 + }
  76 + else if(str == "/exit")
  77 + {
  78 + socket.sendMsg("EXIT_OK");
  79 + kill = true;
  80 + System.out.println(serv.getNickname(this) + " disconnected");
  81 + }
  82 + else
  83 + {
  84 + System.out.println("FROM " + serv.getNickname(this) + ": " + str);
  85 + serv.sendToChat(this,str);
  86 + }
  87 + }
  88 + else
  89 + {
  90 + break;
  91 + }
  92 + }
  93 + sleep = true;
  94 + }
  95 + serv.finishWorker(this);
  96 + }
  97 + }
5 98
6 } 99 }
JChatServer/src/pad/prac2/JChat.java
@@ -6,23 +6,29 @@ public class JChat @@ -6,23 +6,29 @@ public class JChat
6 { 6 {
7 public static void main(String[] args) 7 public static void main(String[] args)
8 { 8 {
  9 +
9 String ip; 10 String ip;
10 int port, roomSize; 11 int port, roomSize;
11 - Scanner in = new Scanner(System.in); 12 + /*Scanner in = new Scanner(System.in);
12 System.out.print("IP: "); 13 System.out.print("IP: ");
13 ip = in.nextLine(); 14 ip = in.nextLine();
14 System.out.print("Port: "); 15 System.out.print("Port: ");
15 port = in.nextInt(); 16 port = in.nextInt();
16 System.out.print("Size of chatroom: "); 17 System.out.print("Size of chatroom: ");
17 roomSize = in.nextInt(); 18 roomSize = in.nextInt();
18 - in.close();  
19 - Server serv = new Server(ip,port,roomSize); 19 + in.close();*/
  20 + ip = "localhost";
  21 + port = 3001;
  22 + roomSize = 3;
  23 + final Server serv = new Server(ip,port,roomSize);
  24 + Runtime.getRuntime().addShutdownHook(new Thread()
  25 + {
  26 + public void run()
  27 + {
  28 + System.out.println("JChat: interrupt catched, killing server...");
  29 + serv.killServer();
  30 + }
  31 + });
20 serv.startServer(); 32 serv.startServer();
21 } 33 }
22 - /*  
23 - * TODO  
24 - *  
25 - * capture SIGINT  
26 - *  
27 - */  
28 } 34 }
JChatServer/src/pad/prac2/MyServerSocket.java
@@ -16,7 +16,9 @@ public class MyServerSocket extends ServerSocket @@ -16,7 +16,9 @@ public class MyServerSocket extends ServerSocket
16 { 16 {
17 try 17 try
18 { 18 {
19 - MySocket incoming = (MySocket)super.accept(); 19 + MySocket incoming = new MySocket();
  20 + super.implAccept(incoming);
  21 + incoming.initializeStreams();
20 return incoming; 22 return incoming;
21 } 23 }
22 catch(IOException ioExc) 24 catch(IOException ioExc)
@@ -31,7 +33,7 @@ public class MyServerSocket extends ServerSocket @@ -31,7 +33,7 @@ public class MyServerSocket extends ServerSocket
31 SocketAddress addr = new InetSocketAddress(ip,port); 33 SocketAddress addr = new InetSocketAddress(ip,port);
32 try 34 try
33 { 35 {
34 - super.bind(addr); 36 + super.bind(addr, 5);
35 } 37 }
36 catch(IOException ioExc) 38 catch(IOException ioExc)
37 { 39 {
JChatServer/src/pad/prac2/MySocket.java
@@ -16,27 +16,32 @@ public class MySocket extends Socket @@ -16,27 +16,32 @@ public class MySocket extends Socket
16 public MySocket() 16 public MySocket()
17 { 17 {
18 super(); 18 super();
  19 + }
  20 +
  21 + public void connect(String host, int port)
  22 + {
  23 + SocketAddress addr = new InetSocketAddress(host,port);
19 try 24 try
20 { 25 {
21 - output = new PrintWriter(super.getOutputStream());  
22 - input = new BufferedReader(new InputStreamReader(super.getInputStream())); 26 + super.connect(addr);
  27 + initializeStreams();
23 } 28 }
24 catch(IOException ioExc) 29 catch(IOException ioExc)
25 { 30 {
26 - System.out.println("TCP: Error initializing socket"); 31 + System.out.println("TCP: Error occured while connecting to remote host");
27 } 32 }
28 } 33 }
29 34
30 - public void connect(String host, int port) 35 + public void initializeStreams()
31 { 36 {
32 - SocketAddress addr = new InetSocketAddress(host,port);  
33 try 37 try
34 { 38 {
35 - super.connect(addr); 39 + output = new PrintWriter(super.getOutputStream());
  40 + input = new BufferedReader(new InputStreamReader(super.getInputStream()));
36 } 41 }
37 catch(IOException ioExc) 42 catch(IOException ioExc)
38 { 43 {
39 - System.out.println("TCP: Error occured while connecting to remote host"); 44 + System.out.println("TCP: Error initializing socket");
40 } 45 }
41 } 46 }
42 47
@@ -54,6 +59,27 @@ public class MySocket extends Socket @@ -54,6 +59,27 @@ public class MySocket extends Socket
54 } 59 }
55 } 60 }
56 61
  62 + public void sendMsg(String msg)
  63 + {
  64 + String length = new Integer(msg.length()).toString();
  65 + this.write(length+'\0', length.length()+1);
  66 + this.write(msg,msg.length());
  67 + }
  68 +
  69 + public String recvMsg()
  70 + {
  71 + String len,str;
  72 + int length;
  73 + len = this.readLine();
  74 + if(len == null)
  75 + {
  76 + return len;
  77 + }
  78 + length = Integer.parseInt(len);
  79 + str = this.read(length);
  80 + return str;
  81 + }
  82 +
57 public void write(String str, int bytes) 83 public void write(String str, int bytes)
58 { 84 {
59 output.print(str.substring(0,bytes)); 85 output.print(str.substring(0,bytes));
@@ -78,7 +104,18 @@ public class MySocket extends Socket @@ -78,7 +104,18 @@ public class MySocket extends Socket
78 { 104 {
79 try 105 try
80 { 106 {
81 - return input.readLine(); 107 + String line = "";
  108 + char[] c = new char[1];
  109 + while(true)
  110 + {
  111 + input.read(c,0,1);
  112 + if(c[0] == '\0')
  113 + {
  114 + break;
  115 + }
  116 + line += c[0];
  117 + }
  118 + return line;
82 } 119 }
83 catch(IOException ioExc) 120 catch(IOException ioExc)
84 { 121 {
JChatServer/src/pad/prac2/Server.java
1 package pad.prac2; 1 package pad.prac2;
2 2
3 -import java.io.BufferedReader;  
4 import java.io.IOException; 3 import java.io.IOException;
5 -import java.io.InputStreamReader;  
6 -import java.io.PrintWriter;  
7 -import java.util.Collection;  
8 import java.util.Iterator; 4 import java.util.Iterator;
  5 +import java.util.Set;
9 import java.util.concurrent.ConcurrentHashMap; 6 import java.util.concurrent.ConcurrentHashMap;
  7 +import java.util.concurrent.locks.Condition;
  8 +import java.util.concurrent.locks.Lock;
  9 +import java.util.concurrent.locks.ReentrantLock;
10 10
11 public class Server 11 public class Server
12 { 12 {
13 private MyServerSocket ss; 13 private MyServerSocket ss;
14 - private BufferedReader stdin;  
15 - private PrintWriter stdout;  
16 private int roomSize; 14 private int roomSize;
17 - private boolean run;  
18 -  
19 - private Worker[] rWorkerPool;  
20 - private Worker[] wWorkerPool;  
21 -  
22 - private ConcurrentHashMap<String,MySocket> activeConnections; 15 + private boolean kill;
  16 + private Connection[] workerPool;
  17 + private int freeWorkers;
  18 + private Lock lock;
  19 + private Condition availableWorkers;
  20 + private ConcurrentHashMap<Connection,String> activeConnections;
23 21
24 public Server(String ip, int port, int rS) 22 public Server(String ip, int port, int rS)
25 { 23 {
26 try 24 try
27 { 25 {
28 ss = new MyServerSocket(); 26 ss = new MyServerSocket();
29 - stdout = new PrintWriter(System.out);  
30 - stdin = new BufferedReader(new InputStreamReader(System.in)); 27 + lock = new ReentrantLock();
  28 + activeConnections = new ConcurrentHashMap<Connection,String>();
31 roomSize = rS; 29 roomSize = rS;
32 - rWorkerPool = new Worker[roomSize];  
33 - wWorkerPool = new Worker[roomSize]; 30 + freeWorkers = roomSize;
  31 + kill = false;
  32 + availableWorkers = lock.newCondition();
  33 + workerPool = new Connection[roomSize];
  34 + for(int i = 0; i < roomSize; i++)
  35 + {
  36 + workerPool[i] = new Connection(this);
  37 + workerPool[i].start();
  38 + }
  39 + ss.bind(ip, port);
34 } 40 }
35 catch(IOException ioExc) 41 catch(IOException ioExc)
36 { 42 {
@@ -38,39 +44,96 @@ public class Server @@ -38,39 +44,96 @@ public class Server
38 } 44 }
39 } 45 }
40 46
41 - public void startServer() 47 + public void sendToChat(Connection origin, String message)
42 { 48 {
43 - 49 + lock.lock();
  50 + String nickname = activeConnections.get(origin);
  51 + Set<Connection> connections = activeConnections.keySet();
  52 + Iterator<Connection> it = connections.iterator();
  53 + Connection conn;
  54 + while(it.hasNext())
  55 + {
  56 + conn = it.next();
  57 + if(conn != origin)
  58 + {
  59 + conn.sendMessage(nickname + ": " + message);
  60 + }
  61 + }
  62 + lock.unlock();
44 } 63 }
45 64
46 - public void startWorker(Worker r, Worker w, MySocket s) 65 + public void startServer()
47 { 66 {
48 - if(r == null) 67 + while(!kill)
49 { 68 {
50 - r = new Worker(s,null,stdout); 69 + MySocket incoming = ss.accept();
  70 + if(incoming != null)
  71 + {
  72 + System.out.println("Accepted connection from " + incoming.getInetAddress());
  73 +
  74 + startWorker(incoming);
  75 + }
51 } 76 }
52 - r.awake();  
53 - if(w == null) 77 +
  78 + }
  79 +
  80 + public void startWorker(MySocket s)
  81 + {
  82 + lock.lock();
  83 + while(freeWorkers == 0)
54 { 84 {
55 - w = new Worker(s,stdin,null); 85 + try
  86 + {
  87 + lock.unlock();
  88 + availableWorkers.await();
  89 + lock.lock();
  90 + }
  91 + catch(InterruptedException intExc)
  92 + {
  93 + intExc.printStackTrace();
  94 + }
56 } 95 }
57 - w.awake(); 96 + workerPool[roomSize - freeWorkers].setSock(s);
  97 + workerPool[roomSize - freeWorkers].awake();
  98 + workerPool[roomSize - freeWorkers] = null;
  99 + freeWorkers--;
  100 + lock.unlock();
  101 + }
  102 +
  103 + public String getNickname(Connection c)
  104 + {
  105 + return activeConnections.get(c);
  106 + }
  107 +
  108 + public void finishWorker(Connection c)
  109 + {
  110 + lock.lock();
  111 + freeWorkers++;
  112 + workerPool[roomSize - freeWorkers] = c;
  113 + availableWorkers.signal();
  114 + lock.unlock();
  115 + }
  116 +
  117 + public void addToChatroom(Connection c, String nickName)
  118 + {
  119 + activeConnections.put(c, nickName);
  120 + System.out.println(nickName + " has entered the room");
58 } 121 }
59 122
60 - public void finishWorkers() 123 + public void finishConnections()
61 { 124 {
62 - Collection<Worker> worerke= activeConnections.values();  
63 - Iterator<MySocket> it = sockets.iterator(); 125 + Set<Connection> conns = activeConnections.keySet();
  126 + Iterator<Connection> it = conns.iterator();
64 while(it.hasNext()) 127 while(it.hasNext())
65 { 128 {
66 - it.next().close(); 129 + it.next().finish();
67 } 130 }
68 } 131 }
69 132
70 public void killServer() 133 public void killServer()
71 { 134 {
72 - run = false; 135 + kill = true;
73 ss.close(); 136 ss.close();
74 - finishWorkers(); 137 + finishConnections();
75 } 138 }
76 } 139 }
JChatServer/src/pad/prac2/Worker.java deleted
1 -package pad.prac2;  
2 -  
3 -import java.io.BufferedReader;  
4 -import java.io.IOException;  
5 -import java.io.PrintWriter;  
6 -  
7 -public class Worker extends Thread  
8 -{  
9 - private PrintWriter output;  
10 - private BufferedReader input;  
11 - private MySocket sock;  
12 - private boolean run;  
13 - private boolean kill;  
14 - private boolean sleep;  
15 - private Server serv;  
16 -  
17 - public Worker(Server srv, MySocket s, BufferedReader i, PrintWriter o)  
18 - {  
19 - sock = s;  
20 - output = o;  
21 - input = i;  
22 - run = false;  
23 - kill = false;  
24 - sleep = true;  
25 - serv = srv;  
26 - }  
27 -  
28 - public void finish()  
29 - {  
30 - kill = true;  
31 - run = false;  
32 - sleep = false;  
33 - sock.close();  
34 - }  
35 -  
36 - public void run()  
37 - {  
38 - while(!kill)  
39 - {  
40 - while(sleep)  
41 - {  
42 - try  
43 - {  
44 - wait();  
45 - }  
46 - catch (InterruptedException e)  
47 - {  
48 - e.printStackTrace();  
49 - }  
50 - }  
51 - while(run)  
52 - {  
53 - if(output == null && input != null)  
54 - {  
55 - String str, length;  
56 - while(true)  
57 - {  
58 - try  
59 - {  
60 - str = input.readLine();  
61 - length = new Integer(str.length()).toString();  
62 - sock.write(length, length.length());  
63 - sock.write(str, str.length());  
64 - }  
65 - catch(IOException ioExc)  
66 - {  
67 - run = false;  
68 - sleep = true;  
69 - break;  
70 - }  
71 - }  
72 - }  
73 - else if(input == null && output != null)  
74 - {  
75 - String len, str;  
76 - while((len = sock.readLine()) != null)  
77 - {  
78 - int length = Integer.parseInt(len);  
79 - str = sock.read(length);  
80 - output.println(str);  
81 - }  
82 - run = false;  
83 - sleep = true;  
84 - }  
85 - }  
86 - }  
87 - }  
88 -  
89 - public void awake()  
90 - {  
91 - run = true;  
92 - sleep = false;  
93 - this.notify();  
94 - }  
95 -}