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 | 5 | * |
6 | 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 | 10 | using namespace std; |
17 | 11 | |
... | ... | @@ -22,24 +16,50 @@ bool connected, finished; |
22 | 16 | el signal SIGPIPE. */ |
23 | 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 | 43 | bool connect(Socket& s) |
30 | 44 | { |
31 | - string host; | |
45 | + string host, nick; | |
32 | 46 | int port; |
33 | - cout << "Hostname: "; | |
47 | + /*cout << "Hostname: "; | |
34 | 48 | cin >> host; |
35 | 49 | cout << "Port: "; |
36 | - cin >> port; | |
50 | + cin >> port;*/ | |
51 | + cout << "Nickname: "; | |
52 | + cin >> nick; | |
37 | 53 | cin.ignore(); |
54 | + host = "localhost"; | |
55 | + port = 3001; | |
56 | + | |
38 | 57 | try |
39 | 58 | { |
40 | 59 | s.Connect(host,port); |
41 | 60 | cout << "Connected" << endl; |
42 | 61 | connected = true; |
62 | + s << nick; | |
43 | 63 | } |
44 | 64 | catch(SocketException& e) |
45 | 65 | { |
... | ... | @@ -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 | 134 | //! Método principal del cliente |
... | ... | @@ -80,71 +136,43 @@ void speedTest(Socket& s) |
80 | 136 | int main() |
81 | 137 | { |
82 | 138 | signal(SIGPIPE, exitClient); |
83 | - signal(SIGINT, exitClient); | |
84 | 139 | Socket s; |
85 | 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 | 148 | s.Create(); |
88 | - while (!exit) | |
149 | + while (!finished) | |
89 | 150 | { |
90 | 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 | 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 | 176 | * list nicks |
149 | 177 | * unicast message |
150 | 178 | */ |
151 | 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 | 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 | 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 | 6 | { |
7 | 7 | public static void main(String[] args) |
8 | 8 | { |
9 | + | |
9 | 10 | String ip; |
10 | 11 | int port, roomSize; |
11 | - Scanner in = new Scanner(System.in); | |
12 | + /*Scanner in = new Scanner(System.in); | |
12 | 13 | System.out.print("IP: "); |
13 | 14 | ip = in.nextLine(); |
14 | 15 | System.out.print("Port: "); |
15 | 16 | port = in.nextInt(); |
16 | 17 | System.out.print("Size of chatroom: "); |
17 | 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 | 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 | 16 | { |
17 | 17 | try |
18 | 18 | { |
19 | - MySocket incoming = (MySocket)super.accept(); | |
19 | + MySocket incoming = new MySocket(); | |
20 | + super.implAccept(incoming); | |
21 | + incoming.initializeStreams(); | |
20 | 22 | return incoming; |
21 | 23 | } |
22 | 24 | catch(IOException ioExc) |
... | ... | @@ -31,7 +33,7 @@ public class MyServerSocket extends ServerSocket |
31 | 33 | SocketAddress addr = new InetSocketAddress(ip,port); |
32 | 34 | try |
33 | 35 | { |
34 | - super.bind(addr); | |
36 | + super.bind(addr, 5); | |
35 | 37 | } |
36 | 38 | catch(IOException ioExc) |
37 | 39 | { | ... | ... |
JChatServer/src/pad/prac2/MySocket.java
... | ... | @@ -16,27 +16,32 @@ public class MySocket extends Socket |
16 | 16 | public MySocket() |
17 | 17 | { |
18 | 18 | super(); |
19 | + } | |
20 | + | |
21 | + public void connect(String host, int port) | |
22 | + { | |
23 | + SocketAddress addr = new InetSocketAddress(host,port); | |
19 | 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 | 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 | 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 | 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 | 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 | 83 | public void write(String str, int bytes) |
58 | 84 | { |
59 | 85 | output.print(str.substring(0,bytes)); |
... | ... | @@ -78,7 +104,18 @@ public class MySocket extends Socket |
78 | 104 | { |
79 | 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 | 120 | catch(IOException ioExc) |
84 | 121 | { | ... | ... |
JChatServer/src/pad/prac2/Server.java
1 | 1 | package pad.prac2; |
2 | 2 | |
3 | -import java.io.BufferedReader; | |
4 | 3 | import java.io.IOException; |
5 | -import java.io.InputStreamReader; | |
6 | -import java.io.PrintWriter; | |
7 | -import java.util.Collection; | |
8 | 4 | import java.util.Iterator; |
5 | +import java.util.Set; | |
9 | 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 | 11 | public class Server |
12 | 12 | { |
13 | 13 | private MyServerSocket ss; |
14 | - private BufferedReader stdin; | |
15 | - private PrintWriter stdout; | |
16 | 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 | 22 | public Server(String ip, int port, int rS) |
25 | 23 | { |
26 | 24 | try |
27 | 25 | { |
28 | 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 | 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 | 41 | catch(IOException ioExc) |
36 | 42 | { |
... | ... | @@ -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 | 127 | while(it.hasNext()) |
65 | 128 | { |
66 | - it.next().close(); | |
129 | + it.next().finish(); | |
67 | 130 | } |
68 | 131 | } |
69 | 132 | |
70 | 133 | public void killServer() |
71 | 134 | { |
72 | - run = false; | |
135 | + kill = true; | |
73 | 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 | -} |