Commit 493ea8e792d6cb2328647617b2621f6681eb2241
1 parent
791d4e1f
git-svn-id: svn://imanolbarba.net/PAD@25 c2ee353e-ed0d-4329-bf56-03aec153487f
Showing
16 changed files
with
402 additions
and
381 deletions
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& s) | @@ -47,32 +67,68 @@ bool connect(Socket& 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& s) | @@ -80,71 +136,43 @@ void speedTest(Socket& 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 | -} |